波场java-tron3.6的签名验证和错误返回值分析

1.验证签名流程分析

本篇文章主要分析波场tron的交易签名验证的流程,汇总在哪些情况下会抛出哪些异常,希望大家在看到相应的报错后能够识别出问题出在哪里。重点不是介绍tron的签名体系。详细关于tron的账户权限机制请参考:https://cn.developers.tron.network/docs/多重签名

签名验证主要是发生在java-tron接收到交易之后,废话不多说直接贴代码:

//验证签名
  //task1:如果之前已经验证通过, 直接返回
  //task2:验证签名总数是否在正确的范围之内
  //task3:验证签名,并处理异常
  public boolean validateSignature(Manager manager)
      throws ValidateSignatureException {
    //----------------------------------------------------------------------
    //task1:如果之前已经验证通过, 直接返回
    //----------------------------------------------------------------------
    if (isVerified == true) {
      return true;
    }

    //----------------------------------------------------------------------
    //task2:验证签名总数是否在正确的范围之内
    //----------------------------------------------------------------------
    //如果签名的总数小于0, 则抛出异常
    if (this.transaction.getSignatureCount() <= 0
        || this.transaction.getRawData().getContractCount() <= 0) {
      throw new ValidateSignatureException("miss sig or contract");
    }
    //如果超过5个签名, 向上抛出异常
    if (this.transaction.getSignatureCount() > manager.getDynamicPropertiesStore()
        .getTotalSignNum()) {
      throw new ValidateSignatureException("too many signatures");
    }
    byte[] hash = this.getRawHash().getBytes();
    //----------------------------------------------------------------------
    //task3:验证签名,并处理异常
    //----------------------------------------------------------------------
    try {
      if (!validateSignature(this.transaction, hash, manager)) {
        isVerified = false;
        throw new ValidateSignatureException("sig error");
      }
    } catch (SignatureException e) {
      isVerified = false;
      throw new ValidateSignatureException(e.getMessage());
    } catch (PermissionException e) {
      isVerified = false;
      throw new ValidateSignatureException(e.getMessage());
    } catch (SignatureFormatException e) {
      isVerified = false;
      throw new ValidateSignatureException(e.getMessage());
    }
    //验证通过,标记验证通过

    isVerified = true;
    return true;
  }

validateSignature(Manager manager)函数是签名验证的入口,这个函数主要分3部分,首先是判断这个交易是不是被验证过, 如果是,则直接返回。第2步是判断交易中签名的个数是否在正常范围之内,由于波场支持多重签名,所以交易中可以存在多个签名,但是每个权限(Permission)最多只能支持5个签名,所以这里判断签名的个数必须大于0,或者小于等于5。如果签名个数没有问题,则直接调用validateSignature(Transaction transaction,
byte[] hash, Manager manager)做签名验证。

	//验证一个交易的签名
  //task1:根据交易的中的permissionid,从账户中获取permission对象
  //task2:根据账户中定义的permission, 检查交易中的所有签名总权重是否达到正确的阀值
  public static boolean validateSignature(Transaction transaction,
      byte[] hash, Manager manager)
      throws PermissionException, SignatureException, SignatureFormatException {
    AccountStore accountStore = manager.getAccountStore();
    //----------------------------------------------------------------------
    //task1:根据交易的中的permissionid,从账户中获取permission对象
    //----------------------------------------------------------------------
    //获取交易中的contract
    Transaction.Contract contract = transaction.getRawData().getContractList().get(0);
    //获取permissionID
    int permissionId = contract.getPermissionId();
    //交易调用方
    byte[] owner = getOwner(contract);
    //获取交易调用方的账户
    AccountCapsule account = accountStore.get(owner);
    Permission permission = null;
    //如果account不存在
    if (account == null) {
      //交易中的指定的permissionid 为0,使用默认的权限
      if (permissionId == 0) {
        permission = AccountCapsule.getDefaultPermission(ByteString.copyFrom(owner));
      }
      //交易中的指定饿permissionid为1, 使用默认的active权限
      if (permissionId == 2) {
        permission = AccountCapsule
            .createDefaultActivePermission(ByteString.copyFrom(owner), manager);
      }
    } else {
      //从账户中获取相应的permissionid
      permission = account.getPermissionById(permissionId);
    }
    //如果账户中的permission不存在,向上抛出异常
    if (permission == null) {
      throw new PermissionException("permission isn't exit");
    }
    //检查操作权限
    if (permissionId != 0) {
      //如果permisionID不能于0, 只能等于2
      if (permission.getType() != PermissionType.Active) {
        throw new PermissionException("Permission type is error");
      }
      //check oprations
      //检查权限,如果没有权限,向上抛出异常
      if (!Wallet.checkPermissionOprations(permission, contract)) {
        throw new PermissionException("Permission denied");
      }
    }
    //----------------------------------------------------------------------
    //task2:根据账户中定义的permission, 检查交易中的所有签名总权重是否达到正确的阀值
    //----------------------------------------------------------------------
    //检查权重是否超过阀值
    long weight = checkWeight(permission, transaction.getSignatureList(), hash, null);
    //检查权限的权重是否超过了阀值
    if (weight >= permission.getThreshold()) {
      return true;
    }
    return false;
  }

validateSignature(Transaction transaction,
byte[] hash, Manager manager)函数主要是根据用户指定的permissionid从账户中取出permission,然后根据permission中签名的要求来验证交易中签名是否正确。
函数中首先就是从交易中抽取了出PermissionId,如果用户发送交易时没有指定PermissionId,java-tron会默认设定为0, 也就是用账户中的owner permission。如果交易发起方账户在链上不存在,则创建一个默认的permission来进行验证,这种情况一般发生在账户创建的交易中。

如果permissionid不为0, 那账户中的permission的类型必须是active。关于多重签名的详细介绍参考:https://cn.developers.tron.network/docs/多重签名。

如果permission类型是active的,还需要检查交易发起方是否具备当前的交易类型的操作权限,checkPermissionOprations函数做操作权限的检查。

如果上述的检查都通过,最后进入权重检查, 也就是统计交易中的签名的总权重,看是否达到了permission的最低要求。

  //计算一个交易中所有签名的权重
  //task1:如果签名的个数超过了该权限允许的地址总个数,向上抛出异常
  //task2:统计所有签名的权重, 同时处理错误的情况
  public static long checkWeight(Permission permission, List<ByteString> sigs, byte[] hash,
      List<ByteString> approveList)
      throws SignatureException, PermissionException, SignatureFormatException {
    long currentWeight = 0;
    // if (signature.size() % 65 != 0) {
    // throw new SignatureFormatException("Signature size is " + signature.size());
    // }
    //----------------------------------------------------------------------
    //task1:如果签名的个数超过了该权限允许的地址总个数,向上抛出异常
    //----------------------------------------------------------------------
    if (sigs.size() > permission.getKeysCount()) {
      throw new PermissionException(
          "Signature count is " + (sigs.size()) + " more than key counts of permission : "
              + permission.getKeysCount());
    }
    //----------------------------------------------------------------------
    //task2:统计所有签名的权重, 同时处理错误的情况
    //----------------------------------------------------------------------
    HashMap addMap = new HashMap();
    for (ByteString sig : sigs) {
      //检查签名格式是否正确
      if (sig.size() < 65) {
        throw new SignatureFormatException(
            "Signature size is " + sig.size());
      }
      String base64 = TransactionCapsule.getBase64FromByteString(sig);
      //从签名中恢复地址
      byte[] address = ECKey.signatureToAddress(hash, base64);
      //获取这个地址的权重
      long weight = getWeight(permission, address);
      //如果这个地址的权重为0, 说明这个地址没有权利签名交易,向上抛出异常
      if (weight == 0) {
        throw new PermissionException(
            ByteArray.toHexString(sig.toByteArray()) + " is signed by " + Wallet
                .encode58Check(address) + " but it is not contained of permission.");
      }
      //检查是否不是存在一个地址多词签名的情况,否则向上抛出异常
      if (addMap.containsKey(base64)) {
        throw new PermissionException(Wallet.encode58Check(address) + " has signed twice!");
      }
      addMap.put(base64, weight);
      if (approveList != null) {
        approveList.add(ByteString.copyFrom(address)); //out put approve list.
      }
      //增加总的权重
      currentWeight += weight;
    }
    return currentWeight;
  }

首先判断交易中的签名总数有没有超过账户permission定义的key的总个数,如果超过了就向上抛出异常。检查通过后,会遍历交易中的签名,判断是否正确,并根据permission中的定义统计交易中签名的总权重,最后将总权重返回。

2.交易签名错误返回总结

报错 原因
miss sig or contract 交易中签名数为0或者交易没有contract
too many signatures 交易中签名书超过5个
permission isn’t exit 账户中不存在permission
Permission type is error 用户指定的permissionid不为0, 但是账户中的permission类型不是active
Permission denied 当前交易发起方账户不具备交易的指定的contract权限
operations size must 32 账户中permission的定义的操作码集合有误
Signature size is xxx 签名数据有误
Signature count is xxx, more than key counts of permission : xxx 签名总数超过了账户定义的key数量
“xxxxx” is signed by “xxxxxx”, but it is not contained of permission. 签名的地址不在账户的permission定义的key列表中
“xxxxx” has signed twice! 交易中存在多签的情况
sig error 签名权重不够

你可能感兴趣的:(tron)