Fabcoin Core  0.16.2
P2P Digital Currency
TransactionQueue.cpp
Go to the documentation of this file.
1 /*
2  This file is part of cpp-ethereum.
3 
4  cpp-ethereum is free software: you can redistribute it and/or modify
5  it under the terms of the GNU General Public License as published by
6  the Free Software Foundation, either version 3 of the License, or
7  (at your option) any later version.
8 
9  cpp-ethereum is distributed in the hope that it will be useful,
10  but WITHOUT ANY WARRANTY; without even the implied warranty of
11  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12  GNU General Public License for more details.
13 
14  You should have received a copy of the GNU General Public License
15  along with cpp-ethereum. If not, see <http://www.gnu.org/licenses/>.
16 */
26 
27 using namespace std;
28 using namespace dev;
29 using namespace dev::eth;
30 using namespace dev::test;
31 
32 BOOST_FIXTURE_TEST_SUITE(TransactionQueueSuite, TestOutputHelper)
33 
35 {
37 
38  // from a94f5374fce5edbc8e2a8697c15331677e6ebf0b
39  const u256 gasCost = 10 * szabo;
40  const u256 gas = 25000;
41  Address dest = Address("0x095e7baea6a6c7c4c2dfeb977efac326af552d87");
42  Address to = Address("0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b");
43  Secret sec = Secret("0x45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8");
44  Transaction tx0(0, gasCost, gas, dest, bytes(), 0, sec );
45  Transaction tx0_1(1, gasCost, gas, dest, bytes(), 0, sec );
46  Transaction tx1(0, gasCost, gas, dest, bytes(), 1, sec );
47  Transaction tx2(0, gasCost, gas, dest, bytes(), 2, sec );
48  Transaction tx9(0, gasCost, gas, dest, bytes(), 9, sec );
49 
50  txq.import(tx0);
51  BOOST_CHECK(1 == txq.maxNonce(to));
52  txq.import(tx0);
53  BOOST_CHECK(1 == txq.maxNonce(to));
54  txq.import(tx0_1);
55  BOOST_CHECK(1 == txq.maxNonce(to));
56  txq.import(tx1);
57  BOOST_CHECK(2 == txq.maxNonce(to));
58  txq.import(tx9);
59  BOOST_CHECK(10 == txq.maxNonce(to));
60  txq.import(tx2);
61  BOOST_CHECK(10 == txq.maxNonce(to));
62 
63 }
64 
66 {
68 
69  const u256 gasCostCheap = 10 * szabo;
70  const u256 gasCostMed = 20 * szabo;
71  const u256 gasCostHigh = 30 * szabo;
72  const u256 gas = 25000;
73  Address dest = Address("0x095e7baea6a6c7c4c2dfeb977efac326af552d87");
74  Secret sender1 = Secret("0x3333333333333333333333333333333333333333333333333333333333333333");
75  Secret sender2 = Secret("0x4444444444444444444444444444444444444444444444444444444444444444");
76  Transaction tx0(0, gasCostCheap, gas, dest, bytes(), 0, sender1 );
77  Transaction tx0_1(1, gasCostMed, gas, dest, bytes(), 0, sender1 );
78  Transaction tx1(0, gasCostCheap, gas, dest, bytes(), 1, sender1 );
79  Transaction tx2(0, gasCostHigh, gas, dest, bytes(), 0, sender2 );
80  Transaction tx3(0, gasCostCheap + 1, gas, dest, bytes(), 1, sender2 );
81  Transaction tx4(0, gasCostHigh, gas, dest, bytes(), 2, sender1 );
82  Transaction tx5(0, gasCostMed, gas, dest, bytes(), 2, sender2 );
83 
84  txq.import(tx0);
85  BOOST_CHECK(Transactions { tx0 } == txq.topTransactions(256));
86  txq.import(tx0);
87  BOOST_CHECK(Transactions { tx0 } == txq.topTransactions(256));
88  txq.import(tx0_1);
89  BOOST_CHECK(Transactions { tx0_1 } == txq.topTransactions(256));
90  txq.import(tx1);
91  BOOST_CHECK((Transactions { tx0_1, tx1 }) == txq.topTransactions(256));
92  txq.import(tx2);
93  BOOST_CHECK((Transactions { tx2, tx0_1, tx1 }) == txq.topTransactions(256));
94  txq.import(tx3);
95  BOOST_CHECK((Transactions { tx2, tx0_1, tx1, tx3 }) == txq.topTransactions(256));
96  txq.import(tx4);
97  BOOST_CHECK((Transactions { tx2, tx0_1, tx1, tx3, tx4 }) == txq.topTransactions(256));
98  txq.import(tx5);
99  BOOST_CHECK((Transactions { tx2, tx0_1, tx1, tx3, tx5, tx4 }) == txq.topTransactions(256));
100 
101  txq.drop(tx0_1.sha3());
102  BOOST_CHECK((Transactions { tx2, tx1, tx3, tx5, tx4 }) == txq.topTransactions(256));
103  txq.drop(tx1.sha3());
104  BOOST_CHECK((Transactions { tx2, tx3, tx5, tx4 }) == txq.topTransactions(256));
105  txq.drop(tx5.sha3());
106  BOOST_CHECK((Transactions { tx2, tx3, tx4 }) == txq.topTransactions(256));
107 
108  Transaction tx6(0, gasCostMed, gas, dest, bytes(), 20, sender1 );
109  txq.import(tx6);
110  BOOST_CHECK((Transactions { tx2, tx3, tx4, tx6 }) == txq.topTransactions(256));
111 
112  Transaction tx7(0, gasCostMed, gas, dest, bytes(), 2, sender2 );
113  txq.import(tx7);
114  // deterministic signature: hash of tx5 and tx7 will be same
115  BOOST_CHECK((Transactions { tx2, tx3, tx4, tx6 }) == txq.topTransactions(256));
116 
117 }
118 
120 {
122 
123  // from a94f5374fce5edbc8e2a8697c15331677e6ebf0b
124  const u256 gasCostMed = 20 * szabo;
125  const u256 gas = 25000;
126  Address dest = Address("0x095e7baea6a6c7c4c2dfeb977efac326af552d87");
127  Secret sender = Secret("0x3333333333333333333333333333333333333333333333333333333333333333");
128  Transaction tx0(0, gasCostMed, gas, dest, bytes(), 0, sender );
129  Transaction tx1(0, gasCostMed, gas, dest, bytes(), 1, sender );
130  Transaction tx2(0, gasCostMed, gas, dest, bytes(), 2, sender );
131  Transaction tx3(0, gasCostMed, gas, dest, bytes(), 3, sender );
132  Transaction tx4(0, gasCostMed, gas, dest, bytes(), 4, sender );
133 
134  txq.import(tx0);
135  txq.import(tx1);
136  txq.import(tx2);
137  txq.import(tx3);
138  txq.import(tx4);
139  BOOST_CHECK((Transactions { tx0, tx1, tx2, tx3, tx4 }) == txq.topTransactions(256));
140 
141  txq.setFuture(tx2.sha3());
142  BOOST_CHECK((Transactions { tx0, tx1 }) == txq.topTransactions(256));
143 
144  Transaction tx2_2(1, gasCostMed, gas, dest, bytes(), 2, sender );
145  txq.import(tx2_2);
146  BOOST_CHECK((Transactions { tx0, tx1, tx2_2, tx3, tx4 }) == txq.topTransactions(256));
147 }
148 
149 
151 {
152  dev::eth::TransactionQueue txq(3, 3);
153  const u256 gasCostMed = 20 * szabo;
154  const u256 gas = 25000;
155  Address dest = Address("0x095e7baea6a6c7c4c2dfeb977efac326af552d87");
156  Secret sender = Secret("0x3333333333333333333333333333333333333333333333333333333333333333");
157  Secret sender2 = Secret("0x4444444444444444444444444444444444444444444444444444444444444444");
158  Transaction tx0(0, gasCostMed, gas, dest, bytes(), 0, sender );
159  Transaction tx1(0, gasCostMed, gas, dest, bytes(), 1, sender );
160  Transaction tx2(0, gasCostMed, gas, dest, bytes(), 2, sender );
161  Transaction tx3(0, gasCostMed, gas, dest, bytes(), 3, sender );
162  Transaction tx4(0, gasCostMed, gas, dest, bytes(), 4, sender );
163  Transaction tx5(0, gasCostMed + 1, gas, dest, bytes(), 0, sender2 );
164 
165  txq.import(tx0);
166  txq.import(tx1);
167  txq.import(tx2);
168  txq.import(tx3);
169  txq.import(tx4);
170  txq.import(tx5);
171  BOOST_CHECK((Transactions { tx5, tx0, tx1 }) == txq.topTransactions(256));
172 }
173 
175 {
176  BOOST_REQUIRE(string(TransactionQueueChannel().name()) == string(EthCyan "┉┅▶"));
177 }
178 
179 
181 {
182  TestTransaction testTransaction = TestTransaction::defaultTransaction();
183  TransactionQueue tq;
184  h256Hash known = tq.knownTransactions();
185  BOOST_REQUIRE(known.size() == 0);
186 
187  ImportResult ir = tq.import(testTransaction.transaction().rlp());
188  BOOST_REQUIRE(ir == ImportResult::Success);
189  known = tq.knownTransactions();
190  BOOST_REQUIRE(known.size() == 1);
191 
192  ir = tq.import(testTransaction.transaction().rlp());
193  BOOST_REQUIRE(ir == ImportResult::AlreadyKnown);
194 
195  bytes rlp = testTransaction.transaction().rlp();
196  rlp.at(0) = 03;
197  ir = tq.import(rlp);
198  BOOST_REQUIRE(ir == ImportResult::Malformed);
199 
200  known = tq.knownTransactions();
201  BOOST_REQUIRE(known.size() == 1);
202 
203  TestTransaction testTransaction2 = TestTransaction::defaultTransaction(1, 2);
204  TestTransaction testTransaction3 = TestTransaction::defaultTransaction(1, 1);
205  TestTransaction testTransaction4 = TestTransaction::defaultTransaction(1, 4);
206  ir = tq.import(testTransaction2.transaction().rlp());
207  ir = tq.import(testTransaction3.transaction().rlp());
208  BOOST_REQUIRE(ir == ImportResult::OverbidGasPrice);
209  ir = tq.import(testTransaction4.transaction().rlp());
210  known = tq.knownTransactions();
211  BOOST_REQUIRE(known.size() == 1);
212  Transactions ts = tq.topTransactions(4);
213  BOOST_REQUIRE(ts.size() == 1);
214  BOOST_REQUIRE(Transaction(ts.at(0)).gasPrice() == 4);
215 
216  tq.setFuture(Transaction(ts.at(0)).sha3());
217  Address from = Transaction(ts.at(0)).from();
218  ts = tq.topTransactions(4);
219  BOOST_REQUIRE(ts.size() == 0);
220  BOOST_REQUIRE(tq.waiting(from) == 1);
221 }
222 
224 {
225  TransactionQueue tq;
226  TestTransaction testTransaction = TestTransaction::defaultTransaction();
227  tq.dropGood(testTransaction.transaction());
228  tq.import(testTransaction.transaction().rlp());
229  BOOST_REQUIRE(tq.topTransactions(4).size() == 1);
230  tq.dropGood(testTransaction.transaction());
231  BOOST_REQUIRE(tq.topTransactions(4).size() == 0);
232 }
233 
235 {
236  TransactionQueue tq(5, 3);
237  Address from;
238  for (size_t i = 1; i < 7; i++)
239  {
240  TestTransaction testTransaction = TestTransaction::defaultTransaction(i);
241  ImportResult res = tq.import(testTransaction.transaction());
242  from = testTransaction.transaction().from();
243  BOOST_REQUIRE(res == ImportResult::Success);
244  }
245 
246  //5 is imported and 6th is dropped
247  BOOST_REQUIRE(tq.waiting(from) == 5);
248 
249  Transactions topTr = tq.topTransactions(10);
250  BOOST_REQUIRE(topTr.size() == 5);
251 
252  for (int i = topTr.size() - 1; i >= 0 ; i--)
253  tq.setFuture(topTr.at(i).sha3());
254 
255  topTr = tq.topTransactions(10);
256  BOOST_REQUIRE(topTr.size() == 0);
257 
258  TestTransaction testTransaction = TestTransaction::defaultTransaction(7);
259  BOOST_REQUIRE(tq.waiting(from) == 5);
260 
261  //Drop out of bound feauture
262  ImportResult res = tq.import(testTransaction.transaction());
263  BOOST_REQUIRE(res == ImportResult::Success);
264 
265  //future list size is now 3 + 1 imported transaction
266  BOOST_REQUIRE(tq.waiting(testTransaction.transaction().from()) == 4);
267 
268  topTr = tq.topTransactions(10);
269  BOOST_REQUIRE(topTr.size() == 1); // 1 imported transaction
270 }
271 
273 {
274  TransactionQueue tq;
275  TestTransaction testTransaction = TestTransaction::defaultTransaction();
276 
277  bytes payloadToDecode = testTransaction.transaction().rlp();
278 
279  RLPStream rlpStream(2);
280  rlpStream.appendRaw(payloadToDecode);
281  rlpStream.appendRaw(payloadToDecode);
282 
283  RLP tRlp(rlpStream.out());
284 
285  //check that Transaction could be recreated from the RLP
286  Transaction tRlpTransaction(payloadToDecode, CheckTransaction::Cheap);
287  BOOST_REQUIRE(tRlpTransaction.data() == testTransaction.transaction().data());
288 
289  //try to import transactions
290  string hashStr = "01020304050607080910111213141516171819202122232425262728293031320102030405060708091011121314151617181920212223242526272829303132";
291  tq.enqueue(tRlp, h512(hashStr));
292  tq.enqueue(tRlp, h512(hashStr));
293  this_thread::sleep_for(chrono::seconds(1));
294 
295  //at least 1 transaction should be imported through RLP
296  Transactions topTr = tq.topTransactions(10);
297  BOOST_REQUIRE(topTr.size() == 1);
298 }
299 
Adapted from code found on http://stackoverflow.com/questions/180947/base64-decode-snippet-in-c Origi...
Definition: Arith256.cpp:15
Address from() const
Synonym for safeSender().
Definition: Transaction.h:128
A queue of Transactions, each stored as RLP.
void enqueue(RLP const &_data, h512 const &_nodeId)
Add transaction to the queue to be verified and imported.
bytes rlp(_T _t)
Export a single item in RLP format, returning a byte array.
Definition: RLP.h:467
#define EthCyan
Definition: Terminal.h:131
bytes const & out() const
Read the byte stream.
Definition: RLP.h:433
h160 Address
An Ethereum address: 20 bytes.
Definition: Common.h:62
std::vector< Transaction > Transactions
Nice name for vector of Transaction.
Definition: Transaction.h:121
void drop(h256 const &_txHash)
Remove transaction from the queue.
SecureFixedHash< 32 > Secret
Definition: Common.h:35
std::hash for asio::adress
Definition: Common.h:323
FixedHash< 64 > h512
Definition: FixedHash.h:339
BOOST_AUTO_TEST_CASE(tqMaxNonce)
ImportResult
Definition: Common.h:97
bytes rlp(IncludeSignature _sig=WithSignature) const
Definition: Transaction.h:107
Transactions topTransactions(unsigned _limit, h256Hash const &_avoid=h256Hash()) const
Get top transactions from the queue.
const char * name
Definition: rest.cpp:36
std::vector< byte > bytes
Definition: Common.h:75
Fixed-size raw-byte array container type, with an API optimised for storing hashes.
Definition: FixedHash.h:47
bytes const & data() const
Definition: Transaction.h:131
h256 sha3(IncludeSignature _sig=WithSignature) const
boost::multiprecision::number< boost::multiprecision::cpp_int_backend< 256, 256, boost::multiprecision::unsigned_magnitude, boost::multiprecision::unchecked, void >> u256
Definition: Common.h:125
ImportResult import(bytes const &_tx, IfDropped _ik=IfDropped::Ignore)
Verify and add transaction to the queue synchronously.
Encodes a transaction, ready to be exported to or freshly imported from RLP.
Definition: Transaction.h:84
void setFuture(h256 const &_t)
Mark transaction as future.
void dropGood(Transaction const &_t)
Drop a trasnaction from the list if exists and move following future trasnactions to current (if any)...
#define BOOST_FIXTURE_TEST_SUITE(a, b)
Definition: object.cpp:14
u256 maxNonce(Address const &_a) const
Get max nonce for an account.
bool sha3(bytesConstRef _input, bytesRef o_output)
Calculate SHA3-256 hash of the given input and load it into the given output.
Definition: SHA3.cpp:214
#define BOOST_AUTO_TEST_SUITE_END()
Definition: object.cpp:16
std::unordered_set< h256 > h256Hash
Definition: FixedHash.h:349
Transaction const & transaction() const
Class for writing to an RLP bytestream.
Definition: RLP.h:383
RLPStream & appendRaw(bytesConstRef _rlp, size_t _itemCount=1)
Appends raw (pre-serialised) RLP data. Use with caution.
Definition: RLP.cpp:230
h256Hash knownTransactions() const
Get a hash set of transactions in the queue.
unsigned waiting(Address const &_a) const
Get number of pending transactions for account.
Class for interpreting Recursive Linear-Prefix Data.
Definition: RLP.h:64
Helper functions to work with json::spirit and test files.
#define BOOST_CHECK(expr)
Definition: object.cpp:17