|
|
|
@ -52,7 +52,7 @@ var ( |
|
|
|
|
testBLSPubKey = "30b2c38b1316da91e068ac3bd8751c0901ef6c02a1d58bc712104918302c6ed03d5894671d0c816dad2b4d303320f202" |
|
|
|
|
testBLSPrvKey = "c6d7603520311f7a4e6aac0b26701fc433b75b38df504cd416ef2b900cd66205" |
|
|
|
|
|
|
|
|
|
gasPrice = big.NewInt(1e9) |
|
|
|
|
gasPrice = big.NewInt(3e10) |
|
|
|
|
gasLimit = big.NewInt(int64(params.TxGasValidatorCreation)) |
|
|
|
|
cost = big.NewInt(1).Mul(gasPrice, gasLimit) |
|
|
|
|
dummyErrorSink = types.NewTransactionErrorSink() |
|
|
|
@ -127,13 +127,13 @@ func stakingCreateValidatorTransaction(key *ecdsa.PrivateKey) (*staking.StakingT |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
gasPrice := big.NewInt(1000000000) |
|
|
|
|
gasPrice := big.NewInt(30000000000) |
|
|
|
|
tx, _ := staking.NewStakingTransaction(0, 1e10, gasPrice, stakePayloadMaker) |
|
|
|
|
return staking.Sign(tx, staking.NewEIP155Signer(tx.ChainID()), key) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
func transaction(shardID uint32, nonce uint64, gaslimit uint64, key *ecdsa.PrivateKey) types.PoolTransaction { |
|
|
|
|
return pricedTransaction(shardID, nonce, gaslimit, big.NewInt(1000000000), key) |
|
|
|
|
return pricedTransaction(shardID, nonce, gaslimit, big.NewInt(30000000000), key) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
func pricedTransaction(shardID uint32, nonce uint64, gaslimit uint64, gasprice *big.Int, key *ecdsa.PrivateKey) types.PoolTransaction { |
|
|
|
@ -307,7 +307,7 @@ func TestInvalidTransactions(t *testing.T) { |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
tx = transaction(0, 1, 100000, key) |
|
|
|
|
pool.gasPrice = big.NewInt(1000000000000) |
|
|
|
|
pool.gasPrice = big.NewInt(300000000000) |
|
|
|
|
if err := pool.AddRemote(tx); err != ErrUnderpriced { |
|
|
|
|
t.Error("expected", ErrUnderpriced, "got", err) |
|
|
|
|
} |
|
|
|
@ -439,7 +439,7 @@ func TestMixedTransactions(t *testing.T) { |
|
|
|
|
goodFromKey, _ := crypto.GenerateKey() |
|
|
|
|
tx := transaction(0, 0, 25000, goodFromKey) |
|
|
|
|
txAddr, _ := deriveSender(tx) |
|
|
|
|
pool.currentState.AddBalance(txAddr, big.NewInt(50100000000000)) |
|
|
|
|
pool.currentState.AddBalance(txAddr, big.NewInt(1503000000000000)) |
|
|
|
|
|
|
|
|
|
errs := pool.AddRemotes(types.PoolTransactions{stx, tx}) |
|
|
|
|
for _, err := range errs { |
|
|
|
@ -472,8 +472,8 @@ func TestBlacklistedTransactions(t *testing.T) { |
|
|
|
|
goodFromAcc, _ := deriveSender(goodTx) |
|
|
|
|
|
|
|
|
|
// Fund from accounts
|
|
|
|
|
pool.currentState.AddBalance(bannedFromAcc, big.NewInt(50100000000000)) |
|
|
|
|
pool.currentState.AddBalance(goodFromAcc, big.NewInt(50100000000000)) |
|
|
|
|
pool.currentState.AddBalance(bannedFromAcc, big.NewInt(1503000000000000)) |
|
|
|
|
pool.currentState.AddBalance(goodFromAcc, big.NewInt(1503000000000000)) |
|
|
|
|
|
|
|
|
|
DefaultTxPoolConfig.Blacklist[bannedToAcc] = struct{}{} |
|
|
|
|
err := pool.AddRemotes(types.PoolTransactions{badTx}) |
|
|
|
@ -506,7 +506,7 @@ func TestTransactionQueue(t *testing.T) { |
|
|
|
|
|
|
|
|
|
tx := transaction(0, 0, 100, key) |
|
|
|
|
from, _ := deriveSender(tx) |
|
|
|
|
pool.currentState.AddBalance(from, big.NewInt(1000000000000)) |
|
|
|
|
pool.currentState.AddBalance(from, big.NewInt(30000000000000)) |
|
|
|
|
pool.lockedReset(nil, nil) |
|
|
|
|
pool.enqueueTx(tx) |
|
|
|
|
|
|
|
|
@ -535,7 +535,7 @@ func TestTransactionQueue(t *testing.T) { |
|
|
|
|
tx2 := transaction(0, 10, 100, key) |
|
|
|
|
tx3 := transaction(0, 11, 100, key) |
|
|
|
|
from, _ = deriveSender(tx1) |
|
|
|
|
pool.currentState.AddBalance(from, big.NewInt(1000000000000)) |
|
|
|
|
pool.currentState.AddBalance(from, big.NewInt(30000000000000)) |
|
|
|
|
pool.lockedReset(nil, nil) |
|
|
|
|
|
|
|
|
|
pool.enqueueTx(tx1) |
|
|
|
@ -577,7 +577,7 @@ func TestTransactionChainFork(t *testing.T) { |
|
|
|
|
addr := crypto.PubkeyToAddress(key.PublicKey) |
|
|
|
|
resetState := func() { |
|
|
|
|
statedb, _ := state.New(common.Hash{}, state.NewDatabase(rawdb.NewMemoryDatabase())) |
|
|
|
|
statedb.AddBalance(addr, big.NewInt(9000000000000000)) |
|
|
|
|
statedb.AddBalance(addr, big.NewInt(9000000000000000000)) |
|
|
|
|
|
|
|
|
|
pool.chain = &testBlockChain{statedb, 1000000, new(event.Feed)} |
|
|
|
|
pool.lockedReset(nil, nil) |
|
|
|
@ -606,7 +606,7 @@ func TestTransactionDoubleNonce(t *testing.T) { |
|
|
|
|
addr := crypto.PubkeyToAddress(key.PublicKey) |
|
|
|
|
resetState := func() { |
|
|
|
|
statedb, _ := state.New(common.Hash{}, state.NewDatabase(rawdb.NewMemoryDatabase())) |
|
|
|
|
statedb.AddBalance(addr, big.NewInt(100000000000000000)) |
|
|
|
|
statedb.AddBalance(addr, big.NewInt(1000000000000000000)) |
|
|
|
|
|
|
|
|
|
pool.chain = &testBlockChain{statedb, 1000000, new(event.Feed)} |
|
|
|
|
pool.lockedReset(nil, nil) |
|
|
|
@ -615,13 +615,13 @@ func TestTransactionDoubleNonce(t *testing.T) { |
|
|
|
|
|
|
|
|
|
signer := types.HomesteadSigner{} |
|
|
|
|
tx1, _ := types.SignTx( |
|
|
|
|
types.NewTransaction(0, common.Address{}, 0, big.NewInt(100), 100000, big.NewInt(1000000000), nil), |
|
|
|
|
types.NewTransaction(0, common.Address{}, 0, big.NewInt(100), 100000, big.NewInt(30000000000), nil), |
|
|
|
|
signer, key) |
|
|
|
|
tx2, _ := types.SignTx( |
|
|
|
|
types.NewTransaction(0, common.Address{}, 0, big.NewInt(100), 1000000, big.NewInt(2000000000), nil), |
|
|
|
|
types.NewTransaction(0, common.Address{}, 0, big.NewInt(100), 1000000, big.NewInt(31000000000), nil), |
|
|
|
|
signer, key) |
|
|
|
|
tx3, _ := types.SignTx( |
|
|
|
|
types.NewTransaction(0, common.Address{}, 0, big.NewInt(100), 1000000, big.NewInt(1000000000), nil), |
|
|
|
|
types.NewTransaction(0, common.Address{}, 0, big.NewInt(100), 1000000, big.NewInt(30000000000), nil), |
|
|
|
|
signer, key) |
|
|
|
|
|
|
|
|
|
// Add the first two transaction, ensure higher priced stays only
|
|
|
|
@ -660,7 +660,7 @@ func TestTransactionMissingNonce(t *testing.T) { |
|
|
|
|
defer pool.Stop() |
|
|
|
|
|
|
|
|
|
addr := crypto.PubkeyToAddress(key.PublicKey) |
|
|
|
|
pool.currentState.AddBalance(addr, big.NewInt(100100000000000)) |
|
|
|
|
pool.currentState.AddBalance(addr, big.NewInt(3003000000000000)) |
|
|
|
|
tx := transaction(0, 1, 100000, key) |
|
|
|
|
if _, err := pool.add(tx, false); err != nil { |
|
|
|
|
t.Error("didn't expect error", err) |
|
|
|
@ -685,7 +685,7 @@ func TestTransactionNonceRecovery(t *testing.T) { |
|
|
|
|
|
|
|
|
|
addr := crypto.PubkeyToAddress(key.PublicKey) |
|
|
|
|
pool.currentState.SetNonce(addr, n) |
|
|
|
|
pool.currentState.AddBalance(addr, big.NewInt(100100000000000)) |
|
|
|
|
pool.currentState.AddBalance(addr, big.NewInt(3003000000000000)) |
|
|
|
|
pool.lockedReset(nil, nil) |
|
|
|
|
|
|
|
|
|
tx := transaction(0, n, 100000, key) |
|
|
|
@ -710,7 +710,7 @@ func TestTransactionDropping(t *testing.T) { |
|
|
|
|
defer pool.Stop() |
|
|
|
|
|
|
|
|
|
account, _ := deriveSender(transaction(0, 0, 0, key)) |
|
|
|
|
pool.currentState.AddBalance(account, big.NewInt(1000000000000)) |
|
|
|
|
pool.currentState.AddBalance(account, big.NewInt(30000000000000)) |
|
|
|
|
|
|
|
|
|
// Add some pending and some queued transactions
|
|
|
|
|
var ( |
|
|
|
@ -749,26 +749,26 @@ func TestTransactionDropping(t *testing.T) { |
|
|
|
|
t.Errorf("total transaction mismatch: have %d, want %d", pool.all.Count(), 6) |
|
|
|
|
} |
|
|
|
|
// Reduce the balance of the account, and check that invalidated transactions are dropped
|
|
|
|
|
pool.currentState.AddBalance(account, big.NewInt(-650000000000)) |
|
|
|
|
pool.currentState.AddBalance(account, big.NewInt(-23000000000000)) |
|
|
|
|
pool.lockedReset(nil, nil) |
|
|
|
|
|
|
|
|
|
if _, ok := pool.pending[account].txs.items[tx0.Nonce()]; !ok { |
|
|
|
|
t.Errorf("funded pending transaction missing: %v", tx0) |
|
|
|
|
} |
|
|
|
|
if _, ok := pool.pending[account].txs.items[tx1.Nonce()]; !ok { |
|
|
|
|
t.Errorf("funded pending transaction missing: %v", tx0) |
|
|
|
|
t.Errorf("funded pending transaction missing: %v", tx1) |
|
|
|
|
} |
|
|
|
|
if _, ok := pool.pending[account].txs.items[tx2.Nonce()]; ok { |
|
|
|
|
t.Errorf("out-of-fund pending transaction present: %v", tx1) |
|
|
|
|
t.Errorf("out-of-fund pending transaction present: %v", tx2) |
|
|
|
|
} |
|
|
|
|
if _, ok := pool.queue[account].txs.items[tx10.Nonce()]; !ok { |
|
|
|
|
t.Errorf("funded queued transaction missing: %v", tx10) |
|
|
|
|
} |
|
|
|
|
if _, ok := pool.queue[account].txs.items[tx11.Nonce()]; !ok { |
|
|
|
|
t.Errorf("funded queued transaction missing: %v", tx10) |
|
|
|
|
t.Errorf("funded queued transaction missing: %v", tx11) |
|
|
|
|
} |
|
|
|
|
if _, ok := pool.queue[account].txs.items[tx12.Nonce()]; ok { |
|
|
|
|
t.Errorf("out-of-fund queued transaction present: %v", tx11) |
|
|
|
|
t.Errorf("out-of-fund queued transaction present: %v", tx12) |
|
|
|
|
} |
|
|
|
|
if pool.all.Count() != 4 { |
|
|
|
|
t.Errorf("total transaction mismatch: have %d, want %d", pool.all.Count(), 4) |
|
|
|
@ -815,7 +815,7 @@ func TestTransactionPostponing(t *testing.T) { |
|
|
|
|
keys[i], _ = crypto.GenerateKey() |
|
|
|
|
accs[i] = crypto.PubkeyToAddress(keys[i].PublicKey) |
|
|
|
|
|
|
|
|
|
pool.currentState.AddBalance(crypto.PubkeyToAddress(keys[i].PublicKey), big.NewInt(50100000000000)) |
|
|
|
|
pool.currentState.AddBalance(crypto.PubkeyToAddress(keys[i].PublicKey), big.NewInt(1500100000000000)) |
|
|
|
|
} |
|
|
|
|
// Add a batch consecutive pending transactions for validation
|
|
|
|
|
txs := types.PoolTransactions{} |
|
|
|
@ -858,7 +858,7 @@ func TestTransactionPostponing(t *testing.T) { |
|
|
|
|
} |
|
|
|
|
// Reduce the balance of the account, and check that transactions are reorganised
|
|
|
|
|
for _, addr := range accs { |
|
|
|
|
pool.currentState.AddBalance(addr, big.NewInt(-1)) |
|
|
|
|
pool.currentState.AddBalance(addr, big.NewInt(-30)) |
|
|
|
|
} |
|
|
|
|
pool.lockedReset(nil, nil) |
|
|
|
|
|
|
|
|
@ -922,7 +922,7 @@ func TestTransactionQueueAccountLimiting(t *testing.T) { |
|
|
|
|
defer pool.Stop() |
|
|
|
|
|
|
|
|
|
account, _ := deriveSender(transaction(0, 0, 0, key)) |
|
|
|
|
pool.currentState.AddBalance(account, big.NewInt(900000000000000)) |
|
|
|
|
pool.currentState.AddBalance(account, big.NewInt(9000000000000000000)) |
|
|
|
|
|
|
|
|
|
// Keep queuing up transactions and make sure all above a limit are dropped
|
|
|
|
|
for i := uint64(1); i <= testTxPoolConfig.AccountQueue+5; i++ { |
|
|
|
@ -977,7 +977,7 @@ func testTransactionQueueGlobalLimiting(t *testing.T, nolocals bool) { |
|
|
|
|
keys := make([]*ecdsa.PrivateKey, 5) |
|
|
|
|
for i := 0; i < len(keys); i++ { |
|
|
|
|
keys[i], _ = crypto.GenerateKey() |
|
|
|
|
pool.currentState.AddBalance(crypto.PubkeyToAddress(keys[i].PublicKey), big.NewInt(1000000000000000)) |
|
|
|
|
pool.currentState.AddBalance(crypto.PubkeyToAddress(keys[i].PublicKey), big.NewInt(30000000000000000)) |
|
|
|
|
} |
|
|
|
|
local := keys[len(keys)-1] |
|
|
|
|
|
|
|
|
@ -1067,14 +1067,14 @@ func testTransactionQueueTimeLimiting(t *testing.T, nolocals bool) { |
|
|
|
|
local, _ := crypto.GenerateKey() |
|
|
|
|
remote, _ := crypto.GenerateKey() |
|
|
|
|
|
|
|
|
|
pool.currentState.AddBalance(crypto.PubkeyToAddress(local.PublicKey), big.NewInt(900000000000000)) |
|
|
|
|
pool.currentState.AddBalance(crypto.PubkeyToAddress(remote.PublicKey), big.NewInt(900000000000000)) |
|
|
|
|
pool.currentState.AddBalance(crypto.PubkeyToAddress(local.PublicKey), big.NewInt(9000000000000000000)) |
|
|
|
|
pool.currentState.AddBalance(crypto.PubkeyToAddress(remote.PublicKey), big.NewInt(9000000000000000000)) |
|
|
|
|
|
|
|
|
|
// Add the two transactions and ensure they both are queued up
|
|
|
|
|
if err := pool.AddLocal(pricedTransaction(0, 1, 100000, big.NewInt(1000000000), local)); err != nil { |
|
|
|
|
if err := pool.AddLocal(pricedTransaction(0, 1, 100000, big.NewInt(100000000000), local)); err != nil { |
|
|
|
|
t.Fatalf("failed to add local transaction: %v", err) |
|
|
|
|
} |
|
|
|
|
if err := pool.AddRemote(pricedTransaction(0, 1, 100000, big.NewInt(1000000000), remote)); err != nil { |
|
|
|
|
if err := pool.AddRemote(pricedTransaction(0, 1, 100000, big.NewInt(100000000000), remote)); err != nil { |
|
|
|
|
t.Fatalf("failed to add remote transaction: %v", err) |
|
|
|
|
} |
|
|
|
|
pending, queued := pool.Stats() |
|
|
|
@ -1123,7 +1123,7 @@ func testTransactionLimitingEquivalency(t *testing.T, origin uint64) { |
|
|
|
|
defer pool1.Stop() |
|
|
|
|
|
|
|
|
|
account1, _ := deriveSender(transaction(0, 0, 0, key1)) |
|
|
|
|
pool1.currentState.AddBalance(account1, big.NewInt(9000000000000000)) |
|
|
|
|
pool1.currentState.AddBalance(account1, big.NewInt(9000000000000000000)) |
|
|
|
|
|
|
|
|
|
for i := uint64(0); i < testTxPoolConfig.AccountQueue+5; i++ { |
|
|
|
|
if err := pool1.AddRemote(transaction(0, origin+i, 100000, key1)); err != nil { |
|
|
|
@ -1135,7 +1135,7 @@ func testTransactionLimitingEquivalency(t *testing.T, origin uint64) { |
|
|
|
|
defer pool2.Stop() |
|
|
|
|
|
|
|
|
|
account2, _ := deriveSender(transaction(0, 0, 0, key2)) |
|
|
|
|
pool2.currentState.AddBalance(account2, big.NewInt(9000000000000000)) |
|
|
|
|
pool2.currentState.AddBalance(account2, big.NewInt(9000000000000000000)) |
|
|
|
|
|
|
|
|
|
txs := types.PoolTransactions{} |
|
|
|
|
for i := uint64(0); i < testTxPoolConfig.AccountQueue+5; i++ { |
|
|
|
@ -1308,12 +1308,12 @@ func TestTransactionPoolRepricingKeepsLocals(t *testing.T) { |
|
|
|
|
// Create transaction (both pending and queued) with a linearly growing gasprice
|
|
|
|
|
for i := uint64(0); i < 500; i++ { |
|
|
|
|
// Add pending
|
|
|
|
|
pTx := pricedTransaction(0, i, 100000, big.NewInt(int64(i*1000000000)), keys[2]) |
|
|
|
|
pTx := pricedTransaction(0, i, 100000, big.NewInt(int64(30000000000+i*1000000000)), keys[2]) |
|
|
|
|
if err := pool.AddLocal(pTx); err != nil { |
|
|
|
|
t.Fatal(err) |
|
|
|
|
} |
|
|
|
|
// Add queued
|
|
|
|
|
qTx := pricedTransaction(0, i+501, 100000, big.NewInt(int64(i*1000000000)), keys[2]) |
|
|
|
|
qTx := pricedTransaction(0, i+501, 100000, big.NewInt(int64(30000000000+i*1000000000)), keys[2]) |
|
|
|
|
if err := pool.AddLocal(qTx); err != nil { |
|
|
|
|
t.Fatal(err) |
|
|
|
|
} |
|
|
|
@ -1381,20 +1381,20 @@ func testTransactionJournaling(t *testing.T, nolocals bool) { |
|
|
|
|
local, _ := crypto.GenerateKey() |
|
|
|
|
remote, _ := crypto.GenerateKey() |
|
|
|
|
|
|
|
|
|
pool.currentState.AddBalance(crypto.PubkeyToAddress(local.PublicKey), big.NewInt(900000000000000)) |
|
|
|
|
pool.currentState.AddBalance(crypto.PubkeyToAddress(remote.PublicKey), big.NewInt(900000000000000)) |
|
|
|
|
pool.currentState.AddBalance(crypto.PubkeyToAddress(local.PublicKey), big.NewInt(9000000000000000000)) |
|
|
|
|
pool.currentState.AddBalance(crypto.PubkeyToAddress(remote.PublicKey), big.NewInt(9000000000000000000)) |
|
|
|
|
|
|
|
|
|
// Add three local and a remote transactions and ensure they are queued up
|
|
|
|
|
if err := pool.AddLocal(pricedTransaction(0, 0, 100000, big.NewInt(1000000000), local)); err != nil { |
|
|
|
|
if err := pool.AddLocal(pricedTransaction(0, 0, 100000, big.NewInt(30000000000), local)); err != nil { |
|
|
|
|
t.Fatalf("failed to add local transaction: %v", err) |
|
|
|
|
} |
|
|
|
|
if err := pool.AddLocal(pricedTransaction(0, 1, 100000, big.NewInt(1000000000), local)); err != nil { |
|
|
|
|
if err := pool.AddLocal(pricedTransaction(0, 1, 100000, big.NewInt(30000000000), local)); err != nil { |
|
|
|
|
t.Fatalf("failed to add local transaction: %v", err) |
|
|
|
|
} |
|
|
|
|
if err := pool.AddLocal(pricedTransaction(0, 2, 100000, big.NewInt(1000000000), local)); err != nil { |
|
|
|
|
if err := pool.AddLocal(pricedTransaction(0, 2, 100000, big.NewInt(30000000000), local)); err != nil { |
|
|
|
|
t.Fatalf("failed to add local transaction: %v", err) |
|
|
|
|
} |
|
|
|
|
if err := pool.AddRemote(pricedTransaction(0, 0, 100000, big.NewInt(1000000000), remote)); err != nil { |
|
|
|
|
if err := pool.AddRemote(pricedTransaction(0, 0, 100000, big.NewInt(30000000000), remote)); err != nil { |
|
|
|
|
t.Fatalf("failed to add remote transaction: %v", err) |
|
|
|
|
} |
|
|
|
|
pending, queued := pool.Stats() |
|
|
|
@ -1475,15 +1475,15 @@ func TestTransactionStatusCheck(t *testing.T) { |
|
|
|
|
keys := make([]*ecdsa.PrivateKey, 3) |
|
|
|
|
for i := 0; i < len(keys); i++ { |
|
|
|
|
keys[i], _ = crypto.GenerateKey() |
|
|
|
|
pool.currentState.AddBalance(crypto.PubkeyToAddress(keys[i].PublicKey), big.NewInt(9000000000000000)) |
|
|
|
|
pool.currentState.AddBalance(crypto.PubkeyToAddress(keys[i].PublicKey), big.NewInt(9000000000000000000)) |
|
|
|
|
} |
|
|
|
|
// Generate and queue a batch of transactions, both pending and queued
|
|
|
|
|
txs := types.PoolTransactions{} |
|
|
|
|
|
|
|
|
|
txs = append(txs, pricedTransaction(0, 0, 100000, big.NewInt(1000000000), keys[0])) // Pending only
|
|
|
|
|
txs = append(txs, pricedTransaction(0, 0, 100000, big.NewInt(1000000000), keys[1])) // Pending and queued
|
|
|
|
|
txs = append(txs, pricedTransaction(0, 2, 100000, big.NewInt(1000000000), keys[1])) |
|
|
|
|
txs = append(txs, pricedTransaction(0, 2, 100000, big.NewInt(1000000000), keys[2])) // Queued only
|
|
|
|
|
txs = append(txs, pricedTransaction(0, 0, 100000, big.NewInt(30000000000), keys[0])) // Pending only
|
|
|
|
|
txs = append(txs, pricedTransaction(0, 0, 100000, big.NewInt(30000000000), keys[1])) // Pending and queued
|
|
|
|
|
txs = append(txs, pricedTransaction(0, 2, 100000, big.NewInt(30000000000), keys[1])) |
|
|
|
|
txs = append(txs, pricedTransaction(0, 2, 100000, big.NewInt(30000000000), keys[2])) // Queued only
|
|
|
|
|
|
|
|
|
|
// Import the transaction and ensure they are correctly added
|
|
|
|
|
pool.AddRemotes(txs) |
|
|
|
@ -1610,4 +1610,4 @@ func benchmarkPoolBatchInsert(b *testing.B, size int) { |
|
|
|
|
for _, batch := range batches { |
|
|
|
|
pool.AddRemotes(batch) |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |