Skip to content

Commit cdbbb0a

Browse files
authored
Merge pull request #5999 from fyyhtx/release_v4.7.6
feat(net): add transaction expiration time check before execution
2 parents 1996f7b + 6c73ede commit cdbbb0a

File tree

7 files changed

+150
-14
lines changed

7 files changed

+150
-14
lines changed

chainbase/src/main/java/org/tron/core/capsule/TransactionCapsule.java

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,7 @@
5959
import org.tron.core.exception.P2pException;
6060
import org.tron.core.exception.PermissionException;
6161
import org.tron.core.exception.SignatureFormatException;
62+
import org.tron.core.exception.TransactionExpirationException;
6263
import org.tron.core.exception.ValidateSignatureException;
6364
import org.tron.core.store.AccountStore;
6465
import org.tron.core.store.DynamicPropertiesStore;
@@ -869,4 +870,12 @@ public void removeRedundantRet() {
869870
this.transaction = transactionBuilder.build();
870871
}
871872
}
873+
874+
public void checkExpiration(long nextSlotTime) throws TransactionExpirationException {
875+
if (getExpiration() < nextSlotTime) {
876+
throw new TransactionExpirationException(String.format(
877+
"Transaction expiration time is %d, but next slot time is %d",
878+
getExpiration(), nextSlotTime));
879+
}
880+
}
872881
}

framework/src/main/java/org/tron/core/Wallet.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -549,6 +549,7 @@ public GrpcAPI.Return broadcastTransaction(Transaction signedTransaction) {
549549
throw new ContractValidateException(ActuatorConstant.CONTRACT_NOT_EXIST);
550550
}
551551
TransactionMessage message = new TransactionMessage(trx.getInstance().toByteArray());
552+
trx.checkExpiration(tronNetDelegate.getNextBlockSlotTime());
552553
dbManager.pushTransaction(trx);
553554
int num = tronNetService.fastBroadcastTransaction(message);
554555
if (num == 0 && minEffectiveConnection != 0) {

framework/src/main/java/org/tron/core/net/TronNetDelegate.java

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -380,4 +380,12 @@ public boolean isBlockUnsolidified() {
380380
return headNum - solidNum >= maxUnsolidifiedBlocks;
381381
}
382382

383+
public long getNextBlockSlotTime() {
384+
long slotCount = 1;
385+
if (chainBaseManager.getDynamicPropertiesStore().getStateFlag() == 1) {
386+
slotCount += chainBaseManager.getDynamicPropertiesStore().getMaintenanceSkipSlots();
387+
}
388+
return chainBaseManager.getDynamicPropertiesStore().getLatestBlockHeaderTimestamp()
389+
+ slotCount * BLOCK_PRODUCED_INTERVAL;
390+
}
383391
}

framework/src/main/java/org/tron/core/net/messagehandler/TransactionsMsgHandler.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
import org.tron.core.config.args.Args;
1414
import org.tron.core.exception.P2pException;
1515
import org.tron.core.exception.P2pException.TypeEnum;
16+
import org.tron.core.exception.TransactionExpirationException;
1617
import org.tron.core.net.TronNetDelegate;
1718
import org.tron.core.net.message.TronMessage;
1819
import org.tron.core.net.message.adv.TransactionMessage;
@@ -128,6 +129,7 @@ private void handleTransaction(PeerConnection peer, TransactionMessage trx) {
128129
}
129130

130131
try {
132+
trx.getTransactionCapsule().checkExpiration(tronNetDelegate.getNextBlockSlotTime());
131133
tronNetDelegate.pushTransaction(trx.getTransactionCapsule());
132134
advService.broadcast(trx);
133135
} catch (P2pException e) {
@@ -137,6 +139,9 @@ private void handleTransaction(PeerConnection peer, TransactionMessage trx) {
137139
peer.setBadPeer(true);
138140
peer.disconnect(ReasonCode.BAD_TX);
139141
}
142+
} catch (TransactionExpirationException e) {
143+
logger.warn("{}. trx: {}, peer: {}",
144+
e.getMessage(), trx.getMessageId(), peer.getInetAddress());
140145
} catch (Exception e) {
141146
logger.error("Trx {} from peer {} process failed", trx.getMessageId(), peer.getInetAddress(),
142147
e);

framework/src/test/java/org/tron/core/db/TransactionExpireTest.java

Lines changed: 66 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -50,19 +50,6 @@ public void init() throws IOException {
5050
context = new TronApplicationContext(DefaultConfig.class);
5151
wallet = context.getBean(Wallet.class);
5252
dbManager = context.getBean(Manager.class);
53-
54-
blockCapsule = new BlockCapsule(
55-
1,
56-
Sha256Hash.wrap(ByteString.copyFrom(
57-
ByteArray.fromHexString(
58-
"0304f784e4e7bae517bcab94c3e0c9214fb4ac7ff9d7d5a937d1f40031f87b81"))),
59-
1,
60-
ByteString.copyFromUtf8("testAddress"));
61-
dbManager.getDynamicPropertiesStore().saveLatestBlockHeaderNumber(blockCapsule.getNum());
62-
dbManager.getDynamicPropertiesStore()
63-
.saveLatestBlockHeaderTimestamp(blockCapsule.getTimeStamp());
64-
dbManager.updateRecentBlock(blockCapsule);
65-
initLocalWitness();
6653
}
6754

6855
private void initLocalWitness() {
@@ -81,6 +68,19 @@ public void removeDb() {
8168

8269
@Test
8370
public void testExpireTransaction() {
71+
blockCapsule = new BlockCapsule(
72+
1,
73+
Sha256Hash.wrap(ByteString.copyFrom(
74+
ByteArray.fromHexString(
75+
"0304f784e4e7bae517bcab94c3e0c9214fb4ac7ff9d7d5a937d1f40031f87b81"))),
76+
1,
77+
ByteString.copyFromUtf8("testAddress"));
78+
dbManager.getDynamicPropertiesStore().saveLatestBlockHeaderNumber(blockCapsule.getNum());
79+
dbManager.getDynamicPropertiesStore()
80+
.saveLatestBlockHeaderTimestamp(blockCapsule.getTimeStamp());
81+
dbManager.updateRecentBlock(blockCapsule);
82+
initLocalWitness();
83+
8484
TransferContract transferContract = TransferContract.newBuilder()
8585
.setAmount(1L)
8686
.setOwnerAddress(ByteString.copyFrom(Args.getLocalWitnesses()
@@ -101,8 +101,61 @@ public void testExpireTransaction() {
101101
Assert.assertEquals(response_code.TRANSACTION_EXPIRATION_ERROR, result.getCode());
102102
}
103103

104+
@Test
105+
public void testExpireTransactionNew() {
106+
blockCapsule = new BlockCapsule(
107+
1,
108+
Sha256Hash.wrap(ByteString.copyFrom(
109+
ByteArray.fromHexString(
110+
"0304f784e4e7bae517bcab94c3e0c9214fb4ac7ff9d7d5a937d1f40031f87b81"))),
111+
System.currentTimeMillis(),
112+
ByteString.copyFromUtf8("testAddress"));
113+
dbManager.getDynamicPropertiesStore().saveLatestBlockHeaderNumber(blockCapsule.getNum());
114+
dbManager.getDynamicPropertiesStore()
115+
.saveLatestBlockHeaderTimestamp(blockCapsule.getTimeStamp());
116+
dbManager.updateRecentBlock(blockCapsule);
117+
initLocalWitness();
118+
byte[] address = Args.getLocalWitnesses()
119+
.getWitnessAccountAddress(CommonParameter.getInstance().isECKeyCryptoEngine());
120+
ByteString addressByte = ByteString.copyFrom(address);
121+
AccountCapsule accountCapsule =
122+
new AccountCapsule(Protocol.Account.newBuilder().setAddress(addressByte).build());
123+
accountCapsule.setBalance(1000_000_000L);
124+
dbManager.getChainBaseManager().getAccountStore()
125+
.put(accountCapsule.createDbKey(), accountCapsule);
126+
127+
TransferContract transferContract = TransferContract.newBuilder()
128+
.setAmount(1L)
129+
.setOwnerAddress(addressByte)
130+
.setToAddress(ByteString.copyFrom(ByteArray.fromHexString(
131+
(Wallet.getAddressPreFixString() + "A389132D6639FBDA4FBC8B659264E6B7C90DB086"))))
132+
.build();
133+
TransactionCapsule transactionCapsule =
134+
new TransactionCapsule(transferContract, ContractType.TransferContract);
135+
transactionCapsule.setReference(blockCapsule.getNum(), blockCapsule.getBlockId().getBytes());
136+
137+
transactionCapsule.setExpiration(System.currentTimeMillis());
138+
transactionCapsule.sign(ByteArray.fromHexString(Args.getLocalWitnesses().getPrivateKey()));
139+
140+
GrpcAPI.Return result = wallet.broadcastTransaction(transactionCapsule.getInstance());
141+
Assert.assertEquals(response_code.TRANSACTION_EXPIRATION_ERROR, result.getCode());
142+
}
143+
104144
@Test
105145
public void testTransactionApprovedList() {
146+
blockCapsule = new BlockCapsule(
147+
1,
148+
Sha256Hash.wrap(ByteString.copyFrom(
149+
ByteArray.fromHexString(
150+
"0304f784e4e7bae517bcab94c3e0c9214fb4ac7ff9d7d5a937d1f40031f87b81"))),
151+
1,
152+
ByteString.copyFromUtf8("testAddress"));
153+
dbManager.getDynamicPropertiesStore().saveLatestBlockHeaderNumber(blockCapsule.getNum());
154+
dbManager.getDynamicPropertiesStore()
155+
.saveLatestBlockHeaderTimestamp(blockCapsule.getTimeStamp());
156+
dbManager.updateRecentBlock(blockCapsule);
157+
initLocalWitness();
158+
106159
byte[] address = Args.getLocalWitnesses()
107160
.getWitnessAccountAddress(CommonParameter.getInstance().isECKeyCryptoEngine());
108161
TransferContract transferContract = TransferContract.newBuilder()

framework/src/test/java/org/tron/core/net/messagehandler/TransactionsMsgHandlerTest.java

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,13 +6,18 @@
66
import java.util.ArrayList;
77
import java.util.List;
88
import java.util.Map;
9+
import java.util.concurrent.BlockingQueue;
910
import java.util.concurrent.ConcurrentHashMap;
11+
import java.util.concurrent.LinkedBlockingQueue;
12+
13+
import lombok.Getter;
1014
import org.joda.time.DateTime;
1115
import org.junit.Assert;
1216
import org.junit.BeforeClass;
1317
import org.junit.Test;
1418
import org.mockito.Mockito;
1519
import org.tron.common.BaseTest;
20+
import org.tron.common.runtime.TvmTestUtils;
1621
import org.tron.common.utils.ByteArray;
1722
import org.tron.core.Constant;
1823
import org.tron.core.config.args.Args;
@@ -75,10 +80,48 @@ public void testProcessMessage() {
7580
transactionsMsgHandler.processMessage(peer, new TransactionsMessage(transactionList));
7681
Assert.assertNull(advInvRequest.get(item));
7782
//Thread.sleep(10);
83+
transactionsMsgHandler.close();
84+
BlockingQueue<TrxEvent> smartContractQueue =
85+
new LinkedBlockingQueue(2);
86+
smartContractQueue.offer(new TrxEvent(null, null));
87+
smartContractQueue.offer(new TrxEvent(null, null));
88+
Field field1 = TransactionsMsgHandler.class.getDeclaredField("smartContractQueue");
89+
field1.setAccessible(true);
90+
field1.set(transactionsMsgHandler, smartContractQueue);
91+
Protocol.Transaction trx1 = TvmTestUtils.generateTriggerSmartContractAndGetTransaction(
92+
ByteArray.fromHexString("121212a9cf"),
93+
ByteArray.fromHexString("121212a9cf"),
94+
ByteArray.fromHexString("123456"),
95+
100, 100000000, 0, 0);
96+
Map<Item, Long> advInvRequest1 = new ConcurrentHashMap<>();
97+
Item item1 = new Item(new TransactionMessage(trx1).getMessageId(),
98+
Protocol.Inventory.InventoryType.TRX);
99+
advInvRequest1.put(item1, 0L);
100+
Mockito.when(peer.getAdvInvRequest()).thenReturn(advInvRequest1);
101+
List<Protocol.Transaction> transactionList1 = new ArrayList<>();
102+
transactionList1.add(trx1);
103+
transactionsMsgHandler.processMessage(peer, new TransactionsMessage(transactionList1));
104+
Assert.assertNull(advInvRequest.get(item1));
78105
} catch (Exception e) {
79106
Assert.fail();
80107
} finally {
81108
transactionsMsgHandler.close();
82109
}
83110
}
111+
112+
class TrxEvent {
113+
114+
@Getter
115+
private PeerConnection peer;
116+
@Getter
117+
private TransactionMessage msg;
118+
@Getter
119+
private long time;
120+
121+
public TrxEvent(PeerConnection peer, TransactionMessage msg) {
122+
this.peer = peer;
123+
this.msg = msg;
124+
this.time = System.currentTimeMillis();
125+
}
126+
}
84127
}

framework/src/test/java/org/tron/core/net/services/AdvServiceTest.java

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55
import java.io.IOException;
66
import java.net.InetSocketAddress;
7+
78
import org.junit.AfterClass;
89
import org.junit.Assert;
910
import org.junit.BeforeClass;
@@ -105,12 +106,28 @@ private void testBroadcast() {
105106
}
106107

107108
private void testTrxBroadcast() {
108-
Protocol.Transaction trx = Protocol.Transaction.newBuilder().build();
109+
Protocol.Transaction trx = Protocol.Transaction.newBuilder()
110+
.setRawData(
111+
Protocol.Transaction.raw.newBuilder()
112+
.setRefBlockNum(1)
113+
.setExpiration(System.currentTimeMillis() + 3000).build()).build();
109114
CommonParameter.getInstance().setValidContractProtoThreadNum(1);
110115
TransactionMessage msg = new TransactionMessage(trx);
111116
service.broadcast(msg);
112117
Item item = new Item(msg.getMessageId(), InventoryType.TRX);
113118
Assert.assertNotNull(service.getMessage(item));
119+
120+
Protocol.Transaction expiredTrx = Protocol.Transaction.newBuilder()
121+
.setRawData(
122+
Protocol.Transaction.raw.newBuilder()
123+
.setRefBlockNum(1)
124+
.setExpiration(System.currentTimeMillis() - 1).build())
125+
.build();
126+
CommonParameter.getInstance().setValidContractProtoThreadNum(1);
127+
TransactionMessage msg1 = new TransactionMessage(expiredTrx);
128+
service.broadcast(msg);
129+
Item item1 = new Item(msg1.getMessageId(), InventoryType.TRX);
130+
Assert.assertNull(service.getMessage(item1));
114131
}
115132

116133
}

0 commit comments

Comments
 (0)