Coverage Summary for Class: BlockTxsValidationRule (co.rsk.validators)
Class |
Class, %
|
Method, %
|
Line, %
|
BlockTxsValidationRule |
100%
(1/1)
|
100%
(3/3)
|
67.6%
(23/34)
|
1 /*
2 * This file is part of RskJ
3 * Copyright (C) 2017 RSK Labs Ltd.
4 *
5 * This program is free software: you can redistribute it and/or modify
6 * it under the terms of the GNU Lesser General Public License as published by
7 * the Free Software Foundation, either version 3 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU Lesser General Public License for more details.
14 *
15 * You should have received a copy of the GNU Lesser General Public License
16 * along with this program. If not, see <http://www.gnu.org/licenses/>.
17 */
18
19 package co.rsk.validators;
20
21 import co.rsk.core.RskAddress;
22 import co.rsk.db.RepositoryLocator;
23 import co.rsk.db.RepositorySnapshot;
24 import co.rsk.panic.PanicProcessor;
25 import org.ethereum.core.Block;
26 import org.ethereum.core.Transaction;
27 import org.slf4j.Logger;
28 import org.slf4j.LoggerFactory;
29
30 import java.math.BigInteger;
31 import java.util.HashMap;
32 import java.util.List;
33 import java.util.Map;
34
35 import static java.math.BigInteger.ONE;
36
37 /**
38 * Validate a transactions list.
39 * It validates each transaction nonce againts the expeced sender account nonce
40 * It allows many transactions with the same sender
41 *
42 * @return true if the transactions are valid, false if any transaction is invalid
43 */
44 public class BlockTxsValidationRule implements BlockParentDependantValidationRule{
45
46 private static final Logger logger = LoggerFactory.getLogger("blockvalidator");
47 private static final PanicProcessor panicProcessor = new PanicProcessor();
48
49 private final RepositoryLocator repositoryLocator;
50
51 public BlockTxsValidationRule(RepositoryLocator repositoryLocator) {
52 this.repositoryLocator = repositoryLocator;
53 }
54
55 @Override
56 public boolean isValid(Block block, Block parent) {
57
58 if(block == null || parent == null) {
59 logger.warn("BlockTxsValidationRule - block or parent are null");
60 return false;
61 }
62
63 List<Transaction> txs = block.getTransactionsList();
64 if (txs.isEmpty()) {
65 return true;
66 }
67
68 RepositorySnapshot parentRepo = repositoryLocator.snapshotAt(parent.getHeader());
69
70 Map<RskAddress, BigInteger> curNonce = new HashMap<>();
71
72 for (Transaction tx : txs) {
73 try {
74 tx.verify();
75 } catch (RuntimeException e) {
76 logger.warn("Unable to verify transaction", e);
77 return false;
78 }
79
80 RskAddress sender = tx.getSender();
81 BigInteger expectedNonce = curNonce.get(sender);
82 if (expectedNonce == null) {
83 expectedNonce = parentRepo.getNonce(sender);
84 }
85 curNonce.put(sender, expectedNonce.add(ONE));
86 BigInteger txNonce = new BigInteger(1, tx.getNonce());
87
88 if (!expectedNonce.equals(txNonce)) {
89 logger.warn("Invalid transaction: Tx nonce {} != expected nonce {} (parent nonce: {}): {}",
90 txNonce, expectedNonce, parentRepo.getNonce(sender), tx);
91
92 panicProcessor.panic("invalidtransaction",
93 String.format("Invalid transaction: Tx nonce %s != expected nonce %s (parent nonce: %s): %s",
94 txNonce, expectedNonce, parentRepo.getNonce(sender), tx.getHash()));
95
96 return false;
97 }
98 }
99
100 return true;
101 }
102 }