From a9bdbae96f700dedac5115583804b4aa0ebbd369 Mon Sep 17 00:00:00 2001 From: federico Date: Thu, 4 Jun 2026 14:47:04 +0800 Subject: [PATCH 1/2] fix(api): bound and truncate sign api signatures --- .../org/tron/core/utils/TransactionUtil.java | 5 +- .../tron/core/capsule/TransactionCapsule.java | 26 +++++- .../src/main/java/org/tron/core/Wallet.java | 32 ++++--- .../test/java/org/tron/core/WalletTest.java | 91 +++++++++++++++++++ .../actuator/utils/TransactionUtilTest.java | 53 +++++++++++ 5 files changed, 190 insertions(+), 17 deletions(-) diff --git a/actuator/src/main/java/org/tron/core/utils/TransactionUtil.java b/actuator/src/main/java/org/tron/core/utils/TransactionUtil.java index 53d6caf5691..673e25836f4 100644 --- a/actuator/src/main/java/org/tron/core/utils/TransactionUtil.java +++ b/actuator/src/main/java/org/tron/core/utils/TransactionUtil.java @@ -186,13 +186,11 @@ public static String makeUpperCamelMethod(String originName) { public TransactionSignWeight getTransactionSignWeight(Transaction trx) { TransactionSignWeight.Builder tswBuilder = TransactionSignWeight.newBuilder(); TransactionExtention.Builder trxExBuilder = TransactionExtention.newBuilder(); - trxExBuilder.setTransaction(trx); trxExBuilder.setTxid(ByteString.copyFrom(Sha256Hash.hash(CommonParameter .getInstance().isECKeyCryptoEngine(), trx.getRawData().toByteArray()))); Return.Builder retBuilder = Return.newBuilder(); retBuilder.setResult(true).setCode(response_code.SUCCESS); trxExBuilder.setResult(retBuilder); - tswBuilder.setTransaction(trxExBuilder); Result.Builder resultBuilder = Result.newBuilder(); if (trx.getRawData().getContractCount() == 0) { @@ -249,6 +247,9 @@ public TransactionSignWeight getTransactionSignWeight(Transaction trx) { } } + trx = TransactionCapsule.truncateSignatures(trx); + trxExBuilder.setTransaction(trx); + tswBuilder.setTransaction(trxExBuilder); tswBuilder.setResult(resultBuilder); return tswBuilder.build(); } diff --git a/chainbase/src/main/java/org/tron/core/capsule/TransactionCapsule.java b/chainbase/src/main/java/org/tron/core/capsule/TransactionCapsule.java index 8724a688548..8e5f7361917 100755 --- a/chainbase/src/main/java/org/tron/core/capsule/TransactionCapsule.java +++ b/chainbase/src/main/java/org/tron/core/capsule/TransactionCapsule.java @@ -18,6 +18,7 @@ import static org.tron.common.utils.StringUtil.encode58Check; import static org.tron.common.utils.WalletUtil.checkPermissionOperations; import static org.tron.core.Constant.MAX_CONTRACT_RESULT_SIZE; +import static org.tron.core.Constant.PER_SIGN_LENGTH; import static org.tron.core.exception.P2pException.TypeEnum.PROTOBUF_ERROR; import com.google.common.primitives.Bytes; @@ -251,7 +252,7 @@ public static long checkWeight(Permission permission, List sigs, byt long weight = getWeight(permission, address); if (weight == 0) { throw new PermissionException( - ByteArray.toHexString(sig.toByteArray()) + " is signed by " + encode58Check(address) + ByteArray.toHexString(hash) + " is signed by " + encode58Check(address) + " but it is not contained of permission."); } if (ForkController.instance().pass(Parameter.ForkBlockVersionEnum.VERSION_4_7_1)) { @@ -465,6 +466,25 @@ public static String getBase64FromByteString(ByteString sign) { return ECDSASignature.fromComponents(rsv.getR(), rsv.getS(), rsv.getV()).toBase64(); } + public static Transaction truncateSignatures(Transaction trx) { + boolean needTruncate = false; + for (ByteString sig : trx.getSignatureList()) { + if (sig.size() > PER_SIGN_LENGTH) { + needTruncate = true; + break; + } + } + if (!needTruncate) { + return trx; + } + Transaction.Builder builder = trx.toBuilder().clearSignature(); + for (ByteString sig : trx.getSignatureList()) { + builder.addSignature( + sig.size() > PER_SIGN_LENGTH ? sig.substring(0, PER_SIGN_LENGTH) : sig); + } + return builder.build(); + } + public static boolean validateSignature(Transaction transaction, byte[] hash, AccountStore accountStore, DynamicPropertiesStore dynamicPropertiesStore) throws PermissionException, SignatureException, SignatureFormatException { @@ -631,7 +651,7 @@ public void addSign(byte[] privateKey, AccountStore accountStore) .signHash(getTransactionId().getBytes()))); this.transaction = this.transaction.toBuilder().addSignature(sig).build(); } - + private static void checkPermission(int permissionId, Permission permission, Transaction.Contract contract) throws PermissionException { if (permissionId != 0) { if (permission.getType() != PermissionType.Active) { @@ -714,7 +734,7 @@ public boolean validateSignature(AccountStore accountStore, } } isVerified = true; - } + } return true; } diff --git a/framework/src/main/java/org/tron/core/Wallet.java b/framework/src/main/java/org/tron/core/Wallet.java index b705b26edc2..3596217bded 100755 --- a/framework/src/main/java/org/tron/core/Wallet.java +++ b/framework/src/main/java/org/tron/core/Wallet.java @@ -228,6 +228,8 @@ import org.tron.protos.Protocol.MarketOrderPairList; import org.tron.protos.Protocol.MarketPrice; import org.tron.protos.Protocol.MarketPriceList; +import org.tron.protos.Protocol.Permission; +import org.tron.protos.Protocol.Permission.PermissionType; import org.tron.protos.Protocol.Proposal; import org.tron.protos.Protocol.Transaction; import org.tron.protos.Protocol.Transaction.Contract; @@ -629,13 +631,11 @@ public GrpcAPI.Return broadcastTransaction(Transaction signedTransaction) { public TransactionApprovedList getTransactionApprovedList(Transaction trx) { TransactionApprovedList.Builder tswBuilder = TransactionApprovedList.newBuilder(); TransactionExtention.Builder trxExBuilder = TransactionExtention.newBuilder(); - trxExBuilder.setTransaction(trx); trxExBuilder.setTxid(ByteString.copyFrom(Sha256Hash.hash(CommonParameter .getInstance().isECKeyCryptoEngine(), trx.getRawData().toByteArray()))); Return.Builder retBuilder = Return.newBuilder(); retBuilder.setResult(true).setCode(response_code.SUCCESS); trxExBuilder.setResult(retBuilder); - tswBuilder.setTransaction(trxExBuilder); TransactionApprovedList.Result.Builder resultBuilder = TransactionApprovedList.Result .newBuilder(); @@ -650,21 +650,26 @@ public TransactionApprovedList getTransactionApprovedList(Transaction trx) { if (account == null) { throw new PermissionException("Account does not exist!"); } + int permissionId = contract.getPermissionId(); + Permission permission = account.getPermissionById(permissionId); + if (permission == null) { + throw new PermissionException("Permission for this, does not exist!"); + } + if (permissionId != 0) { + if (permission.getType() != PermissionType.Active) { + throw new PermissionException("Permission type is wrong!"); + } + //check operations + if (!WalletUtil.checkPermissionOperations(permission, contract)) { + throw new PermissionException("Permission denied!"); + } + } if (trx.getSignatureCount() > 0) { List approveList = new ArrayList(); byte[] hash = Sha256Hash.hash(CommonParameter .getInstance().isECKeyCryptoEngine(), trx.getRawData().toByteArray()); - for (ByteString sig : trx.getSignatureList()) { - if (sig.size() < 65) { - throw new SignatureFormatException( - "Signature size is " + sig.size()); - } - String base64 = TransactionCapsule.getBase64FromByteString(sig); - byte[] address = SignUtils.signatureToAddress(hash, base64, Args.getInstance() - .isECKeyCryptoEngine()); - approveList.add(ByteString.copyFrom(address)); //out put approve list. - } + TransactionCapsule.checkWeight(permission, trx.getSignatureList(), hash, approveList); tswBuilder.addAllApprovedList(approveList); } resultBuilder.setCode(TransactionApprovedList.Result.response_code.SUCCESS); @@ -680,6 +685,9 @@ public TransactionApprovedList getTransactionApprovedList(Transaction trx) { } } + trx = TransactionCapsule.truncateSignatures(trx); + trxExBuilder.setTransaction(trx); + tswBuilder.setTransaction(trxExBuilder); tswBuilder.setResult(resultBuilder); return tswBuilder.build(); } diff --git a/framework/src/test/java/org/tron/core/WalletTest.java b/framework/src/test/java/org/tron/core/WalletTest.java index 0df8d6cdc2c..b00ceb5e9bf 100644 --- a/framework/src/test/java/org/tron/core/WalletTest.java +++ b/framework/src/test/java/org/tron/core/WalletTest.java @@ -1440,5 +1440,96 @@ public void testGetSolidBlock() { Block block = wallet.getSolidBlock(); assertEquals(block2, block); } + + @Test + public void testGetTransactionApprovedListSignatureBound() { + ECKey ecKey = new ECKey(Utils.getRandom()); + AccountCapsule owner = new AccountCapsule( + ByteString.copyFromUtf8("approved-owner"), + ByteString.copyFrom(ecKey.getAddress()), + Protocol.AccountType.Normal, + initBalance); + chainBaseManager.getAccountStore().put(ecKey.getAddress(), owner); + // Default owner permission: a single key with weight 1, so keysCount == 1. + int keysCount = owner.getPermissionById(0).getKeysCount(); + assertEquals(1, keysCount); + + Transaction unsigned = Transaction.newBuilder().setRawData( + Transaction.raw.newBuilder().addContract( + Contract.newBuilder().setType(ContractType.TransferContract) + .setParameter(Any.pack(TransferContract.newBuilder().setAmount(1) + .setOwnerAddress(ByteString.copyFrom(ecKey.getAddress())) + .setToAddress(ByteString.copyFrom( + ByteArray.fromHexString(RECEIVER_ADDRESS))) + .build())).build()).build()).build(); + + // One valid 65-byte [r][s][recId] signature by the owner. + TransactionCapsule capsule = new TransactionCapsule(unsigned); + capsule.sign(ecKey.getPrivKeyBytes()); + ByteString oneSig = capsule.getInstance().getSignature(0); + + // Within keysCount: the single valid signature is recovered, result is SUCCESS. + GrpcAPI.TransactionApprovedList okList = wallet.getTransactionApprovedList( + unsigned.toBuilder().addSignature(oneSig).build()); + assertEquals(GrpcAPI.TransactionApprovedList.Result.response_code.SUCCESS, + okList.getResult().getCode()); + assertEquals(1, okList.getApprovedListCount()); + + // More signatures than keysCount: checkWeight rejects before recovering any of them, + // so the unbounded ecrecover loop can no longer be triggered. + Transaction.Builder overLimit = unsigned.toBuilder(); + for (int i = 0; i < keysCount + 1; i++) { + overLimit.addSignature(oneSig); + } + GrpcAPI.TransactionApprovedList rejected = + wallet.getTransactionApprovedList(overLimit.build()); + assertEquals(GrpcAPI.TransactionApprovedList.Result.response_code.OTHER_ERROR, + rejected.getResult().getCode()); + assertEquals(0, rejected.getApprovedListCount()); + Assert.assertTrue(rejected.getResult().getMessage().contains("more than key counts")); + } + + @Test + public void testGetTransactionApprovedListTruncatesOversizedSignature() { + ECKey ecKey = new ECKey(Utils.getRandom()); + AccountCapsule owner = new AccountCapsule( + ByteString.copyFromUtf8("approved-owner-trunc"), + ByteString.copyFrom(ecKey.getAddress()), + Protocol.AccountType.Normal, + initBalance); + chainBaseManager.getAccountStore().put(ecKey.getAddress(), owner); + + Transaction unsigned = Transaction.newBuilder().setRawData( + Transaction.raw.newBuilder().addContract( + Contract.newBuilder().setType(ContractType.TransferContract) + .setParameter(Any.pack(TransferContract.newBuilder().setAmount(1) + .setOwnerAddress(ByteString.copyFrom(ecKey.getAddress())) + .setToAddress(ByteString.copyFrom( + ByteArray.fromHexString(RECEIVER_ADDRESS))) + .build())).build()).build()).build(); + + TransactionCapsule capsule = new TransactionCapsule(unsigned); + capsule.sign(ecKey.getPrivKeyBytes()); + ByteString validSig = capsule.getInstance().getSignature(0); + assertEquals(65, validSig.size()); + + // Pad the 65-byte signature with trailing junk bytes. + ByteString oversized = validSig.concat( + ByteString.copyFrom(new byte[] {1, 2, 3, 4, 5})); + assertEquals(70, oversized.size()); + + GrpcAPI.TransactionApprovedList reply = wallet.getTransactionApprovedList( + unsigned.toBuilder().addSignature(oversized).build()); + + // Recovery still succeeds and resolves the owner. + assertEquals(GrpcAPI.TransactionApprovedList.Result.response_code.SUCCESS, + reply.getResult().getCode()); + assertEquals(1, reply.getApprovedListCount()); + // The echoed-back transaction has the signature truncated to 65 bytes. + Transaction echoed = reply.getTransaction().getTransaction(); + assertEquals(1, echoed.getSignatureCount()); + assertEquals(65, echoed.getSignature(0).size()); + assertEquals(validSig, echoed.getSignature(0)); + } } diff --git a/framework/src/test/java/org/tron/core/actuator/utils/TransactionUtilTest.java b/framework/src/test/java/org/tron/core/actuator/utils/TransactionUtilTest.java index 15842bfa2c8..7740e6bd0d6 100644 --- a/framework/src/test/java/org/tron/core/actuator/utils/TransactionUtilTest.java +++ b/framework/src/test/java/org/tron/core/actuator/utils/TransactionUtilTest.java @@ -13,18 +13,23 @@ import static org.tron.core.utils.TransactionUtil.validAssetName; import static org.tron.core.utils.TransactionUtil.validTokenAbbrName; +import com.google.protobuf.Any; import com.google.protobuf.ByteString; import java.nio.charset.StandardCharsets; import java.util.ArrayList; import java.util.List; +import javax.annotation.Resource; import lombok.extern.slf4j.Slf4j; import org.junit.Assert; import org.junit.Before; import org.junit.BeforeClass; import org.junit.Test; +import org.tron.api.GrpcAPI.TransactionSignWeight; import org.tron.common.BaseTest; import org.tron.common.TestConstants; +import org.tron.common.crypto.ECKey; import org.tron.common.utils.ByteArray; +import org.tron.common.utils.Utils; import org.tron.core.ChainBaseManager; import org.tron.core.Constant; import org.tron.core.Wallet; @@ -36,14 +41,19 @@ import org.tron.protos.Protocol; import org.tron.protos.Protocol.AccountType; import org.tron.protos.Protocol.Transaction; +import org.tron.protos.Protocol.Transaction.Contract; import org.tron.protos.Protocol.Transaction.Contract.ContractType; import org.tron.protos.contract.BalanceContract.DelegateResourceContract; +import org.tron.protos.contract.BalanceContract.TransferContract; @Slf4j(topic = "capsule") public class TransactionUtilTest extends BaseTest { private static String OWNER_ADDRESS; + @Resource + private TransactionUtil transactionUtil; + /** * Init . */ @@ -452,4 +462,47 @@ public void testConcurrentToString() throws InterruptedException { } Assert.assertTrue(true); } + + @Test + public void testGetTransactionSignWeightTruncatesOversizedSignature() { + ECKey ecKey = new ECKey(Utils.getRandom()); + AccountCapsule owner = new AccountCapsule( + ByteString.copyFromUtf8("sign-weight-owner"), + ByteString.copyFrom(ecKey.getAddress()), + AccountType.Normal, + 10_000_000_000L); + chainBaseManager.getAccountStore().put(ecKey.getAddress(), owner); + + Transaction unsigned = Transaction.newBuilder().setRawData( + Transaction.raw.newBuilder().addContract( + Contract.newBuilder().setType(ContractType.TransferContract) + .setParameter(Any.pack(TransferContract.newBuilder().setAmount(1) + .setOwnerAddress(ByteString.copyFrom(ecKey.getAddress())) + .setToAddress(ByteString.copyFrom( + ByteArray.fromHexString(OWNER_ADDRESS))) + .build())).build()).build()).build(); + + TransactionCapsule capsule = new TransactionCapsule(unsigned); + capsule.sign(ecKey.getPrivKeyBytes()); + ByteString validSig = capsule.getInstance().getSignature(0); + assertEquals(65, validSig.size()); + + // Pad the 65-byte signature with trailing junk bytes. + ByteString oversized = validSig.concat( + ByteString.copyFrom(new byte[] {1, 2, 3, 4, 5})); + assertEquals(70, oversized.size()); + + TransactionSignWeight reply = transactionUtil.getTransactionSignWeight( + unsigned.toBuilder().addSignature(oversized).build()); + + // Recovery still resolves the owner (weight reached the default threshold). + assertEquals(TransactionSignWeight.Result.response_code.ENOUGH_PERMISSION, + reply.getResult().getCode()); + assertEquals(1, reply.getApprovedListCount()); + // The echoed-back transaction has the signature truncated to 65 bytes. + Transaction echoed = reply.getTransaction().getTransaction(); + assertEquals(1, echoed.getSignatureCount()); + assertEquals(65, echoed.getSignature(0).size()); + assertEquals(validSig, echoed.getSignature(0)); + } } From 52ae0b58260ab622e6f6a4b18e7a576efd11d8aa Mon Sep 17 00:00:00 2001 From: federico Date: Thu, 4 Jun 2026 18:55:47 +0800 Subject: [PATCH 2/2] fix(api): add sign count guard and move truncation to entry --- .../org/tron/core/utils/TransactionUtil.java | 16 ++++++-- .../src/main/java/org/tron/core/Wallet.java | 20 ++++++--- .../test/java/org/tron/core/WalletTest.java | 41 ++++++++++++++++++- .../actuator/utils/TransactionUtilTest.java | 39 +++++++++++++++++- 4 files changed, 103 insertions(+), 13 deletions(-) diff --git a/actuator/src/main/java/org/tron/core/utils/TransactionUtil.java b/actuator/src/main/java/org/tron/core/utils/TransactionUtil.java index 673e25836f4..13600ff5380 100644 --- a/actuator/src/main/java/org/tron/core/utils/TransactionUtil.java +++ b/actuator/src/main/java/org/tron/core/utils/TransactionUtil.java @@ -185,13 +185,24 @@ public static String makeUpperCamelMethod(String originName) { public TransactionSignWeight getTransactionSignWeight(Transaction trx) { TransactionSignWeight.Builder tswBuilder = TransactionSignWeight.newBuilder(); + Result.Builder resultBuilder = Result.newBuilder(); + if (trx.getSignatureCount() > chainBaseManager.getDynamicPropertiesStore() + .getTotalSignNum()) { + resultBuilder.setCode(Result.response_code.OTHER_ERROR); + resultBuilder.setMessage("too many signatures"); + tswBuilder.setResult(resultBuilder); + return tswBuilder.build(); + } + + trx = TransactionCapsule.truncateSignatures(trx); TransactionExtention.Builder trxExBuilder = TransactionExtention.newBuilder(); + trxExBuilder.setTransaction(trx); trxExBuilder.setTxid(ByteString.copyFrom(Sha256Hash.hash(CommonParameter .getInstance().isECKeyCryptoEngine(), trx.getRawData().toByteArray()))); Return.Builder retBuilder = Return.newBuilder(); retBuilder.setResult(true).setCode(response_code.SUCCESS); trxExBuilder.setResult(retBuilder); - Result.Builder resultBuilder = Result.newBuilder(); + tswBuilder.setTransaction(trxExBuilder); if (trx.getRawData().getContractCount() == 0) { resultBuilder.setCode(Result.response_code.OTHER_ERROR); @@ -247,9 +258,6 @@ public TransactionSignWeight getTransactionSignWeight(Transaction trx) { } } - trx = TransactionCapsule.truncateSignatures(trx); - trxExBuilder.setTransaction(trx); - tswBuilder.setTransaction(trxExBuilder); tswBuilder.setResult(resultBuilder); return tswBuilder.build(); } diff --git a/framework/src/main/java/org/tron/core/Wallet.java b/framework/src/main/java/org/tron/core/Wallet.java index 3596217bded..28c73eb0c44 100755 --- a/framework/src/main/java/org/tron/core/Wallet.java +++ b/framework/src/main/java/org/tron/core/Wallet.java @@ -630,14 +630,25 @@ public GrpcAPI.Return broadcastTransaction(Transaction signedTransaction) { public TransactionApprovedList getTransactionApprovedList(Transaction trx) { TransactionApprovedList.Builder tswBuilder = TransactionApprovedList.newBuilder(); + TransactionApprovedList.Result.Builder resultBuilder = TransactionApprovedList.Result + .newBuilder(); + if (trx.getSignatureCount() > chainBaseManager.getDynamicPropertiesStore() + .getTotalSignNum()) { + resultBuilder.setCode(TransactionApprovedList.Result.response_code.OTHER_ERROR); + resultBuilder.setMessage("too many signatures"); + tswBuilder.setResult(resultBuilder); + return tswBuilder.build(); + } + + trx = TransactionCapsule.truncateSignatures(trx); TransactionExtention.Builder trxExBuilder = TransactionExtention.newBuilder(); + trxExBuilder.setTransaction(trx); trxExBuilder.setTxid(ByteString.copyFrom(Sha256Hash.hash(CommonParameter .getInstance().isECKeyCryptoEngine(), trx.getRawData().toByteArray()))); Return.Builder retBuilder = Return.newBuilder(); retBuilder.setResult(true).setCode(response_code.SUCCESS); trxExBuilder.setResult(retBuilder); - TransactionApprovedList.Result.Builder resultBuilder = TransactionApprovedList.Result - .newBuilder(); + tswBuilder.setTransaction(trxExBuilder); if (trx.getRawData().getContractCount() == 0) { resultBuilder.setCode(TransactionApprovedList.Result.response_code.OTHER_ERROR); @@ -666,7 +677,7 @@ public TransactionApprovedList getTransactionApprovedList(Transaction trx) { } if (trx.getSignatureCount() > 0) { - List approveList = new ArrayList(); + List approveList = new ArrayList<>(); byte[] hash = Sha256Hash.hash(CommonParameter .getInstance().isECKeyCryptoEngine(), trx.getRawData().toByteArray()); TransactionCapsule.checkWeight(permission, trx.getSignatureList(), hash, approveList); @@ -685,9 +696,6 @@ public TransactionApprovedList getTransactionApprovedList(Transaction trx) { } } - trx = TransactionCapsule.truncateSignatures(trx); - trxExBuilder.setTransaction(trx); - tswBuilder.setTransaction(trxExBuilder); tswBuilder.setResult(resultBuilder); return tswBuilder.build(); } diff --git a/framework/src/test/java/org/tron/core/WalletTest.java b/framework/src/test/java/org/tron/core/WalletTest.java index b00ceb5e9bf..137a5fc551b 100644 --- a/framework/src/test/java/org/tron/core/WalletTest.java +++ b/framework/src/test/java/org/tron/core/WalletTest.java @@ -1442,7 +1442,7 @@ public void testGetSolidBlock() { } @Test - public void testGetTransactionApprovedListSignatureBound() { + public void testApprovedListSigBound() { ECKey ecKey = new ECKey(Utils.getRandom()); AccountCapsule owner = new AccountCapsule( ByteString.copyFromUtf8("approved-owner"), @@ -1490,7 +1490,7 @@ public void testGetTransactionApprovedListSignatureBound() { } @Test - public void testGetTransactionApprovedListTruncatesOversizedSignature() { + public void testApprovedListSigTruncate() { ECKey ecKey = new ECKey(Utils.getRandom()); AccountCapsule owner = new AccountCapsule( ByteString.copyFromUtf8("approved-owner-trunc"), @@ -1531,5 +1531,42 @@ public void testGetTransactionApprovedListTruncatesOversizedSignature() { assertEquals(65, echoed.getSignature(0).size()); assertEquals(validSig, echoed.getSignature(0)); } + + @Test + public void testApprovedListTooManySigs() { + ECKey ecKey = new ECKey(Utils.getRandom()); + AccountCapsule owner = new AccountCapsule( + ByteString.copyFromUtf8("total-sign-num-owner"), + ByteString.copyFrom(ecKey.getAddress()), + Protocol.AccountType.Normal, + initBalance); + chainBaseManager.getAccountStore().put(ecKey.getAddress(), owner); + + Transaction unsigned = Transaction.newBuilder().setRawData( + Transaction.raw.newBuilder().addContract( + Contract.newBuilder().setType(ContractType.TransferContract) + .setParameter(Any.pack(TransferContract.newBuilder().setAmount(1) + .setOwnerAddress(ByteString.copyFrom(ecKey.getAddress())) + .setToAddress(ByteString.copyFrom( + ByteArray.fromHexString(RECEIVER_ADDRESS))) + .build())).build()).build()).build(); + + TransactionCapsule capsule = new TransactionCapsule(unsigned); + capsule.sign(ecKey.getPrivKeyBytes()); + ByteString oneSig = capsule.getInstance().getSignature(0); + + int totalSignNum = chainBaseManager.getDynamicPropertiesStore().getTotalSignNum(); + Transaction.Builder overLimit = unsigned.toBuilder(); + for (int i = 0; i < totalSignNum + 1; i++) { + overLimit.addSignature(oneSig); + } + + GrpcAPI.TransactionApprovedList rejected = + wallet.getTransactionApprovedList(overLimit.build()); + assertEquals(GrpcAPI.TransactionApprovedList.Result.response_code.OTHER_ERROR, + rejected.getResult().getCode()); + Assert.assertTrue(rejected.getResult().getMessage().contains("too many signatures")); + assertEquals(0, rejected.getApprovedListCount()); + } } diff --git a/framework/src/test/java/org/tron/core/actuator/utils/TransactionUtilTest.java b/framework/src/test/java/org/tron/core/actuator/utils/TransactionUtilTest.java index 7740e6bd0d6..54e611e0aac 100644 --- a/framework/src/test/java/org/tron/core/actuator/utils/TransactionUtilTest.java +++ b/framework/src/test/java/org/tron/core/actuator/utils/TransactionUtilTest.java @@ -464,7 +464,7 @@ public void testConcurrentToString() throws InterruptedException { } @Test - public void testGetTransactionSignWeightTruncatesOversizedSignature() { + public void testSignWeightSigTruncate() { ECKey ecKey = new ECKey(Utils.getRandom()); AccountCapsule owner = new AccountCapsule( ByteString.copyFromUtf8("sign-weight-owner"), @@ -505,4 +505,41 @@ public void testGetTransactionSignWeightTruncatesOversizedSignature() { assertEquals(65, echoed.getSignature(0).size()); assertEquals(validSig, echoed.getSignature(0)); } + + @Test + public void testSignWeightTooManySigs() { + ECKey ecKey = new ECKey(Utils.getRandom()); + AccountCapsule owner = new AccountCapsule( + ByteString.copyFromUtf8("sign-weight-total-num"), + ByteString.copyFrom(ecKey.getAddress()), + AccountType.Normal, + 10_000_000_000L); + chainBaseManager.getAccountStore().put(ecKey.getAddress(), owner); + + Transaction unsigned = Transaction.newBuilder().setRawData( + Transaction.raw.newBuilder().addContract( + Contract.newBuilder().setType(ContractType.TransferContract) + .setParameter(Any.pack(TransferContract.newBuilder().setAmount(1) + .setOwnerAddress(ByteString.copyFrom(ecKey.getAddress())) + .setToAddress(ByteString.copyFrom( + ByteArray.fromHexString(OWNER_ADDRESS))) + .build())).build()).build()).build(); + + TransactionCapsule capsule = new TransactionCapsule(unsigned); + capsule.sign(ecKey.getPrivKeyBytes()); + ByteString oneSig = capsule.getInstance().getSignature(0); + + int totalSignNum = chainBaseManager.getDynamicPropertiesStore().getTotalSignNum(); + Transaction.Builder overLimit = unsigned.toBuilder(); + for (int i = 0; i < totalSignNum + 1; i++) { + overLimit.addSignature(oneSig); + } + + TransactionSignWeight reply = transactionUtil.getTransactionSignWeight( + overLimit.build()); + assertEquals(TransactionSignWeight.Result.response_code.OTHER_ERROR, + reply.getResult().getCode()); + Assert.assertTrue(reply.getResult().getMessage().contains("too many signatures")); + assertEquals(0, reply.getApprovedListCount()); + } }