教程 | 使用WeBASE进行“两阶段交易”
“两阶段交易”是什么?“两阶段交易”是指分成两个步骤发送交易,即对交易编码并签名、将交易提交到链上这两个阶段:
第一阶段:构造并获取交易编码值,并通过私钥对交易编码值签名; 第二阶段:发送交易,也就是将已签名的编码值发送到链上。


值得一提的是,调用 /trans/convertRawTxStr/withSign 接口时:
如果传入了 signUserId 非空,则返回的交易体编码值是通过 signUserId 对应私钥签名后的交易体编码值。 如果传入的 signUserId 为空,则返回的是未签名的交易体编码值,开发者也可以通过JAVA-SDK用私钥对该值签名。




public void testSign(TransactionEncoderService encoderService, RawTransaction rawTransaction) {// 未签名的交易编码值String encodedTransaction = "0xf8a9a001b41b2cc71fe0bf0450f1fa4d820209b6686a8f226d217be0bc51cd9fc4a020018405f5e100820204941f2dfecfd75b883b51762aef6326d3ae9ad5230180b8644ed3885e000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000033132330000000000000000000000000000000000000000000000000000000000010180";// 私钥String privateKey = "0x123";// ECDSA 加密套件CryptoSuite cryptoSuite = new CryptoSuite(CryptoType.ECDSA_TYPE);// 对待签名的编码值作哈运算String hashMessageStr = cryptoSuite.hash(encodedTransaction);System.out.println("hashMessageStr: " + hashMessageStr);// 创建私钥对CryptoKeyPair myKeyPair = cryptoSuite.createKeyPair(privateKey);// 对交易编码值签名SignatureResult signedTx = cryptoSuite.sign(hashMessageStr, myKeyPair);// 获得最终签名后的交易编码值byte[] signedTransaction = encoderService.encode(rawTransaction, signedTx);// 转十六进制字符串String signedTransactionStr = Numeric.toHexString(signedTransaction);System.out.println("signedTransactionStr: " + signedTransactionStr);}


// 构造Function实例Function function = new Function(funcName, contractFunction.getFinalInputs(),contractFunction.getFinalOutputs());// 编码FunctionFunctionEncoder functionEncoder = new FunctionEncoder(cryptoSuite);String encodedFunction = functionEncoder.encode(function);
// 构造交易体BigInteger randomId = new BigInteger(250, new SecureRandom());BigInteger blockLimit = web3j.getBlockLimit();RawTransaction rawTransaction =RawTransaction.createTransaction(randomId, Constants.GAS_PRICE,Constants.GAS_LIMIT, blockLimit, contractAddress, BigInteger.ZERO, encodedFunction,new BigInteger(Constants.chainId), BigInteger.valueOf(groupId), "");// 编码交易体RawTransactionTransactionEncoderService encoderService = new TransactionEncoderService(cryptoSuite);byte[] encodedTransaction = encoderService.encode(rawTransaction, null);
对交易编码值签名前,WeBASE-Front 中会根据传入的 user 字段和 isLocal 字段判断:
如果 user 字段为空,则将 encodedTransaction 转为十六进制后返回。该值就是第一阶段未签名的交易编码值。 如果 user 字段非空, isLocal 字段为 true,则 user 为 WeBASE-Front 本地的用户私钥,通过本地私钥对交易编码值 encodedTransaction 签名。注意,签名前还需对 encodedTransaction 进行一次哈希运算后再签名。 如果 user 字段非空, isLocal 字段为 false,则 user 为 WeBASE-Sign 托管私钥的signUserId,通过签名服务对交易体编码值 encodedTransaction 签名。注意,此处签名前没有对 encodedTransaction 进行哈希,而是直接转为十六进制发到签名服务,签名服务拿到该值后再做哈希运算并签名返回结果。
// encodedTransaction转十六进制String hashMessageStr = Numeric.toHexString(encodedTransaction);// 通过WeBASE-Sign签名EncodeInfo encodeInfo = new EncodeInfo(user, hashMessageStr);String signDataStr = keyStoreService.getSignData(encodeInfo);// 反序列化签名结果SignatureResult signData = CommonUtils.stringToSignatureData(signDataStr, cryptoSuite.cryptoTypeConfig);// 加入签名结果,再次编码byte[] signedMessage = encoderService.encode(rawTransaction, userSignResult);// 转为十六进制String signResultStr = Numeric.toHexString(signedMessage);
// 通过CryptoSuite实例计算signResultStr的交易哈希值String transHash = cryptoSuite.hash(signResultStr);
即刻使用
上述优化及功能所涉及的最新代码和技术文档已同步更新,欢迎体验和star支持。如需咨询技术问题,欢迎本公众号对话框回复【小助手】进技术交流群。

评论
