@@ -1440,5 +1440,133 @@ public void testGetSolidBlock() {
14401440 Block block = wallet .getSolidBlock ();
14411441 assertEquals (block2 , block );
14421442 }
1443+
1444+ @ Test
1445+ public void testApprovedListSigBound () {
1446+ ECKey ecKey = new ECKey (Utils .getRandom ());
1447+ AccountCapsule owner = new AccountCapsule (
1448+ ByteString .copyFromUtf8 ("approved-owner" ),
1449+ ByteString .copyFrom (ecKey .getAddress ()),
1450+ Protocol .AccountType .Normal ,
1451+ initBalance );
1452+ chainBaseManager .getAccountStore ().put (ecKey .getAddress (), owner );
1453+ // Default owner permission: a single key with weight 1, so keysCount == 1.
1454+ int keysCount = owner .getPermissionById (0 ).getKeysCount ();
1455+ assertEquals (1 , keysCount );
1456+
1457+ Transaction unsigned = Transaction .newBuilder ().setRawData (
1458+ Transaction .raw .newBuilder ().addContract (
1459+ Contract .newBuilder ().setType (ContractType .TransferContract )
1460+ .setParameter (Any .pack (TransferContract .newBuilder ().setAmount (1 )
1461+ .setOwnerAddress (ByteString .copyFrom (ecKey .getAddress ()))
1462+ .setToAddress (ByteString .copyFrom (
1463+ ByteArray .fromHexString (RECEIVER_ADDRESS )))
1464+ .build ())).build ()).build ()).build ();
1465+
1466+ // One valid 65-byte [r][s][recId] signature by the owner.
1467+ TransactionCapsule capsule = new TransactionCapsule (unsigned );
1468+ capsule .sign (ecKey .getPrivKeyBytes ());
1469+ ByteString oneSig = capsule .getInstance ().getSignature (0 );
1470+
1471+ // Within keysCount: the single valid signature is recovered, result is SUCCESS.
1472+ GrpcAPI .TransactionApprovedList okList = wallet .getTransactionApprovedList (
1473+ unsigned .toBuilder ().addSignature (oneSig ).build ());
1474+ assertEquals (GrpcAPI .TransactionApprovedList .Result .response_code .SUCCESS ,
1475+ okList .getResult ().getCode ());
1476+ assertEquals (1 , okList .getApprovedListCount ());
1477+
1478+ // More signatures than keysCount: checkWeight rejects before recovering any of them,
1479+ // so the unbounded ecrecover loop can no longer be triggered.
1480+ Transaction .Builder overLimit = unsigned .toBuilder ();
1481+ for (int i = 0 ; i < keysCount + 1 ; i ++) {
1482+ overLimit .addSignature (oneSig );
1483+ }
1484+ GrpcAPI .TransactionApprovedList rejected =
1485+ wallet .getTransactionApprovedList (overLimit .build ());
1486+ assertEquals (GrpcAPI .TransactionApprovedList .Result .response_code .OTHER_ERROR ,
1487+ rejected .getResult ().getCode ());
1488+ assertEquals (0 , rejected .getApprovedListCount ());
1489+ Assert .assertFalse (rejected .getResult ().getMessage ().isEmpty ());
1490+ }
1491+
1492+ @ Test
1493+ public void testApprovedListSigTruncate () {
1494+ ECKey ecKey = new ECKey (Utils .getRandom ());
1495+ AccountCapsule owner = new AccountCapsule (
1496+ ByteString .copyFromUtf8 ("approved-owner-trunc" ),
1497+ ByteString .copyFrom (ecKey .getAddress ()),
1498+ Protocol .AccountType .Normal ,
1499+ initBalance );
1500+ chainBaseManager .getAccountStore ().put (ecKey .getAddress (), owner );
1501+
1502+ Transaction unsigned = Transaction .newBuilder ().setRawData (
1503+ Transaction .raw .newBuilder ().addContract (
1504+ Contract .newBuilder ().setType (ContractType .TransferContract )
1505+ .setParameter (Any .pack (TransferContract .newBuilder ().setAmount (1 )
1506+ .setOwnerAddress (ByteString .copyFrom (ecKey .getAddress ()))
1507+ .setToAddress (ByteString .copyFrom (
1508+ ByteArray .fromHexString (RECEIVER_ADDRESS )))
1509+ .build ())).build ()).build ()).build ();
1510+
1511+ TransactionCapsule capsule = new TransactionCapsule (unsigned );
1512+ capsule .sign (ecKey .getPrivKeyBytes ());
1513+ ByteString validSig = capsule .getInstance ().getSignature (0 );
1514+ assertEquals (65 , validSig .size ());
1515+
1516+ // Pad the 65-byte signature with trailing junk bytes.
1517+ ByteString oversized = validSig .concat (
1518+ ByteString .copyFrom (new byte [] {1 , 2 , 3 , 4 , 5 }));
1519+ assertEquals (70 , oversized .size ());
1520+
1521+ GrpcAPI .TransactionApprovedList reply = wallet .getTransactionApprovedList (
1522+ unsigned .toBuilder ().addSignature (oversized ).build ());
1523+
1524+ // Recovery still succeeds and resolves the owner.
1525+ assertEquals (GrpcAPI .TransactionApprovedList .Result .response_code .SUCCESS ,
1526+ reply .getResult ().getCode ());
1527+ assertEquals (1 , reply .getApprovedListCount ());
1528+ // The echoed-back transaction has the signature truncated to 65 bytes.
1529+ Transaction echoed = reply .getTransaction ().getTransaction ();
1530+ assertEquals (1 , echoed .getSignatureCount ());
1531+ assertEquals (65 , echoed .getSignature (0 ).size ());
1532+ assertEquals (validSig , echoed .getSignature (0 ));
1533+ }
1534+
1535+ @ Test
1536+ public void testApprovedListTooManySigs () {
1537+ ECKey ecKey = new ECKey (Utils .getRandom ());
1538+ AccountCapsule owner = new AccountCapsule (
1539+ ByteString .copyFromUtf8 ("total-sign-num-owner" ),
1540+ ByteString .copyFrom (ecKey .getAddress ()),
1541+ Protocol .AccountType .Normal ,
1542+ initBalance );
1543+ chainBaseManager .getAccountStore ().put (ecKey .getAddress (), owner );
1544+
1545+ Transaction unsigned = Transaction .newBuilder ().setRawData (
1546+ Transaction .raw .newBuilder ().addContract (
1547+ Contract .newBuilder ().setType (ContractType .TransferContract )
1548+ .setParameter (Any .pack (TransferContract .newBuilder ().setAmount (1 )
1549+ .setOwnerAddress (ByteString .copyFrom (ecKey .getAddress ()))
1550+ .setToAddress (ByteString .copyFrom (
1551+ ByteArray .fromHexString (RECEIVER_ADDRESS )))
1552+ .build ())).build ()).build ()).build ();
1553+
1554+ TransactionCapsule capsule = new TransactionCapsule (unsigned );
1555+ capsule .sign (ecKey .getPrivKeyBytes ());
1556+ ByteString oneSig = capsule .getInstance ().getSignature (0 );
1557+
1558+ int totalSignNum = chainBaseManager .getDynamicPropertiesStore ().getTotalSignNum ();
1559+ Transaction .Builder overLimit = unsigned .toBuilder ();
1560+ for (int i = 0 ; i < totalSignNum + 1 ; i ++) {
1561+ overLimit .addSignature (oneSig );
1562+ }
1563+
1564+ GrpcAPI .TransactionApprovedList rejected =
1565+ wallet .getTransactionApprovedList (overLimit .build ());
1566+ assertEquals (GrpcAPI .TransactionApprovedList .Result .response_code .OTHER_ERROR ,
1567+ rejected .getResult ().getCode ());
1568+ Assert .assertTrue (rejected .getResult ().getMessage ().contains ("too many signatures" ));
1569+ assertEquals (0 , rejected .getApprovedListCount ());
1570+ }
14431571}
14441572
0 commit comments