Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 10 additions & 1 deletion actuator/src/main/java/org/tron/core/utils/TransactionUtil.java
Original file line number Diff line number Diff line change
Expand Up @@ -185,6 +185,16 @@ 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
Expand All @@ -193,7 +203,6 @@ public TransactionSignWeight getTransactionSignWeight(Transaction trx) {
retBuilder.setResult(true).setCode(response_code.SUCCESS);
trxExBuilder.setResult(retBuilder);
tswBuilder.setTransaction(trxExBuilder);
Result.Builder resultBuilder = Result.newBuilder();

if (trx.getRawData().getContractCount() == 0) {
resultBuilder.setCode(Result.response_code.OTHER_ERROR);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -251,7 +252,7 @@ public static long checkWeight(Permission permission, List<ByteString> 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)) {
Expand Down Expand Up @@ -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 {
Expand Down Expand Up @@ -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) {
Expand Down Expand Up @@ -714,7 +734,7 @@ public boolean validateSignature(AccountStore accountStore,
}
}
isVerified = true;
}
}
return true;
}

Expand Down
42 changes: 29 additions & 13 deletions framework/src/main/java/org/tron/core/Wallet.java
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -628,6 +630,17 @@ 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
Expand All @@ -636,8 +649,6 @@ public TransactionApprovedList getTransactionApprovedList(Transaction trx) {
retBuilder.setResult(true).setCode(response_code.SUCCESS);
trxExBuilder.setResult(retBuilder);
tswBuilder.setTransaction(trxExBuilder);
TransactionApprovedList.Result.Builder resultBuilder = TransactionApprovedList.Result
.newBuilder();

if (trx.getRawData().getContractCount() == 0) {
resultBuilder.setCode(TransactionApprovedList.Result.response_code.OTHER_ERROR);
Expand All @@ -650,21 +661,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!");
Comment thread
Federico2014 marked this conversation as resolved.
}
}

if (trx.getSignatureCount() > 0) {
List<ByteString> approveList = new ArrayList<ByteString>();
List<ByteString> 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);
Comment thread
Federico2014 marked this conversation as resolved.
tswBuilder.addAllApprovedList(approveList);
}
resultBuilder.setCode(TransactionApprovedList.Result.response_code.SUCCESS);
Expand Down
128 changes: 128 additions & 0 deletions framework/src/test/java/org/tron/core/WalletTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -1440,5 +1440,133 @@ public void testGetSolidBlock() {
Block block = wallet.getSolidBlock();
assertEquals(block2, block);
}

@Test
public void testApprovedListSigBound() {
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 testApprovedListSigTruncate() {
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));
}

@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());
}
}

Loading
Loading