Compare commits
2 Commits
txpool-new
...
token-reco
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
6b614dc2bc | ||
|
|
1cb217250c |
@@ -24,6 +24,7 @@ import (
|
|||||||
"github.com/ethereum/go-ethereum"
|
"github.com/ethereum/go-ethereum"
|
||||||
"github.com/ethereum/go-ethereum/common"
|
"github.com/ethereum/go-ethereum/common"
|
||||||
"github.com/ethereum/go-ethereum/core/types"
|
"github.com/ethereum/go-ethereum/core/types"
|
||||||
|
"github.com/ethereum/go-ethereum/internal/ethapi"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
@@ -100,7 +101,7 @@ type ContractTransactor interface {
|
|||||||
PendingNonceAt(ctx context.Context, account common.Address) (uint64, error)
|
PendingNonceAt(ctx context.Context, account common.Address) (uint64, error)
|
||||||
|
|
||||||
// SendTransactionConditional injects the conditional transaction into the pending pool for execution after verification.
|
// SendTransactionConditional injects the conditional transaction into the pending pool for execution after verification.
|
||||||
SendTransactionConditional(ctx context.Context, tx *types.Transaction, opts types.TransactionOpts) error
|
SendTransactionConditional(ctx context.Context, tx *types.Transaction, opts ethapi.TransactionOpts) error
|
||||||
}
|
}
|
||||||
|
|
||||||
// DeployBackend wraps the operations needed by WaitMined and WaitDeployed.
|
// DeployBackend wraps the operations needed by WaitMined and WaitDeployed.
|
||||||
|
|||||||
@@ -31,6 +31,7 @@ import (
|
|||||||
"github.com/ethereum/go-ethereum/common/hexutil"
|
"github.com/ethereum/go-ethereum/common/hexutil"
|
||||||
"github.com/ethereum/go-ethereum/core/types"
|
"github.com/ethereum/go-ethereum/core/types"
|
||||||
"github.com/ethereum/go-ethereum/crypto"
|
"github.com/ethereum/go-ethereum/crypto"
|
||||||
|
"github.com/ethereum/go-ethereum/internal/ethapi"
|
||||||
"github.com/ethereum/go-ethereum/rlp"
|
"github.com/ethereum/go-ethereum/rlp"
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
)
|
)
|
||||||
@@ -75,7 +76,7 @@ func (mt *mockTransactor) SendTransaction(ctx context.Context, tx *types.Transac
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (mt *mockTransactor) SendTransactionConditional(ctx context.Context, tx *types.Transaction, opts types.TransactionOpts) error {
|
func (mt *mockTransactor) SendTransactionConditional(ctx context.Context, tx *types.Transaction, opts ethapi.TransactionOpts) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -92,7 +92,6 @@ var (
|
|||||||
utils.TxPoolGlobalSlotsFlag,
|
utils.TxPoolGlobalSlotsFlag,
|
||||||
utils.TxPoolAccountQueueFlag,
|
utils.TxPoolAccountQueueFlag,
|
||||||
utils.TxPoolGlobalQueueFlag,
|
utils.TxPoolGlobalQueueFlag,
|
||||||
utils.TxPoolOverflowPoolSlotsFlag,
|
|
||||||
utils.TxPoolLifetimeFlag,
|
utils.TxPoolLifetimeFlag,
|
||||||
utils.TxPoolReannounceTimeFlag,
|
utils.TxPoolReannounceTimeFlag,
|
||||||
utils.BlobPoolDataDirFlag,
|
utils.BlobPoolDataDirFlag,
|
||||||
|
|||||||
@@ -458,12 +458,6 @@ var (
|
|||||||
Value: ethconfig.Defaults.TxPool.GlobalQueue,
|
Value: ethconfig.Defaults.TxPool.GlobalQueue,
|
||||||
Category: flags.TxPoolCategory,
|
Category: flags.TxPoolCategory,
|
||||||
}
|
}
|
||||||
TxPoolOverflowPoolSlotsFlag = &cli.Uint64Flag{
|
|
||||||
Name: "txpool.overflowpoolslots",
|
|
||||||
Usage: "Maximum number of transaction slots in overflow pool",
|
|
||||||
Value: ethconfig.Defaults.TxPool.OverflowPoolSlots,
|
|
||||||
Category: flags.TxPoolCategory,
|
|
||||||
}
|
|
||||||
TxPoolLifetimeFlag = &cli.DurationFlag{
|
TxPoolLifetimeFlag = &cli.DurationFlag{
|
||||||
Name: "txpool.lifetime",
|
Name: "txpool.lifetime",
|
||||||
Usage: "Maximum amount of time non-executable transaction are queued",
|
Usage: "Maximum amount of time non-executable transaction are queued",
|
||||||
@@ -1795,9 +1789,6 @@ func setTxPool(ctx *cli.Context, cfg *legacypool.Config) {
|
|||||||
if ctx.IsSet(TxPoolGlobalQueueFlag.Name) {
|
if ctx.IsSet(TxPoolGlobalQueueFlag.Name) {
|
||||||
cfg.GlobalQueue = ctx.Uint64(TxPoolGlobalQueueFlag.Name)
|
cfg.GlobalQueue = ctx.Uint64(TxPoolGlobalQueueFlag.Name)
|
||||||
}
|
}
|
||||||
if ctx.IsSet(TxPoolOverflowPoolSlotsFlag.Name) {
|
|
||||||
cfg.OverflowPoolSlots = ctx.Uint64(TxPoolOverflowPoolSlotsFlag.Name)
|
|
||||||
}
|
|
||||||
if ctx.IsSet(TxPoolLifetimeFlag.Name) {
|
if ctx.IsSet(TxPoolLifetimeFlag.Name) {
|
||||||
cfg.Lifetime = ctx.Duration(TxPoolLifetimeFlag.Name)
|
cfg.Lifetime = ctx.Duration(TxPoolLifetimeFlag.Name)
|
||||||
}
|
}
|
||||||
@@ -2328,7 +2319,6 @@ func EnableNodeInfo(poolConfig *legacypool.Config, nodeInfo *p2p.NodeInfo) Setup
|
|||||||
"GlobalSlots": poolConfig.GlobalSlots,
|
"GlobalSlots": poolConfig.GlobalSlots,
|
||||||
"AccountQueue": poolConfig.AccountQueue,
|
"AccountQueue": poolConfig.AccountQueue,
|
||||||
"GlobalQueue": poolConfig.GlobalQueue,
|
"GlobalQueue": poolConfig.GlobalQueue,
|
||||||
"OverflowPoolSlots": poolConfig.OverflowPoolSlots,
|
|
||||||
"Lifetime": poolConfig.Lifetime,
|
"Lifetime": poolConfig.Lifetime,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -19,7 +19,6 @@ package legacypool
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
|
||||||
"math"
|
"math"
|
||||||
"math/big"
|
"math/big"
|
||||||
"sort"
|
"sort"
|
||||||
@@ -104,7 +103,6 @@ var (
|
|||||||
queuedGauge = metrics.NewRegisteredGauge("txpool/queued", nil)
|
queuedGauge = metrics.NewRegisteredGauge("txpool/queued", nil)
|
||||||
localGauge = metrics.NewRegisteredGauge("txpool/local", nil)
|
localGauge = metrics.NewRegisteredGauge("txpool/local", nil)
|
||||||
slotsGauge = metrics.NewRegisteredGauge("txpool/slots", nil)
|
slotsGauge = metrics.NewRegisteredGauge("txpool/slots", nil)
|
||||||
OverflowPoolGauge = metrics.NewRegisteredGauge("txpool/overflowpool", nil)
|
|
||||||
|
|
||||||
reheapTimer = metrics.NewRegisteredTimer("txpool/reheap", nil)
|
reheapTimer = metrics.NewRegisteredTimer("txpool/reheap", nil)
|
||||||
)
|
)
|
||||||
@@ -139,7 +137,6 @@ type Config struct {
|
|||||||
GlobalSlots uint64 // Maximum number of executable transaction slots for all accounts
|
GlobalSlots uint64 // Maximum number of executable transaction slots for all accounts
|
||||||
AccountQueue uint64 // Maximum number of non-executable transaction slots permitted per account
|
AccountQueue uint64 // Maximum number of non-executable transaction slots permitted per account
|
||||||
GlobalQueue uint64 // Maximum number of non-executable transaction slots for all accounts
|
GlobalQueue uint64 // Maximum number of non-executable transaction slots for all accounts
|
||||||
OverflowPoolSlots uint64 // Maximum number of transaction slots in overflow pool
|
|
||||||
|
|
||||||
Lifetime time.Duration // Maximum amount of time non-executable transaction are queued
|
Lifetime time.Duration // Maximum amount of time non-executable transaction are queued
|
||||||
ReannounceTime time.Duration // Duration for announcing local pending transactions again
|
ReannounceTime time.Duration // Duration for announcing local pending transactions again
|
||||||
@@ -157,7 +154,6 @@ var DefaultConfig = Config{
|
|||||||
GlobalSlots: 4096 + 1024, // urgent + floating queue capacity with 4:1 ratio
|
GlobalSlots: 4096 + 1024, // urgent + floating queue capacity with 4:1 ratio
|
||||||
AccountQueue: 64,
|
AccountQueue: 64,
|
||||||
GlobalQueue: 1024,
|
GlobalQueue: 1024,
|
||||||
OverflowPoolSlots: 0,
|
|
||||||
|
|
||||||
Lifetime: 3 * time.Hour,
|
Lifetime: 3 * time.Hour,
|
||||||
ReannounceTime: 10 * 365 * 24 * time.Hour,
|
ReannounceTime: 10 * 365 * 24 * time.Hour,
|
||||||
@@ -239,8 +235,6 @@ type LegacyPool struct {
|
|||||||
all *lookup // All transactions to allow lookups
|
all *lookup // All transactions to allow lookups
|
||||||
priced *pricedList // All transactions sorted by price
|
priced *pricedList // All transactions sorted by price
|
||||||
|
|
||||||
localBufferPool *TxOverflowPool // Local buffer transactions
|
|
||||||
|
|
||||||
reqResetCh chan *txpoolResetRequest
|
reqResetCh chan *txpoolResetRequest
|
||||||
reqPromoteCh chan *accountSet
|
reqPromoteCh chan *accountSet
|
||||||
queueTxEventCh chan *types.Transaction
|
queueTxEventCh chan *types.Transaction
|
||||||
@@ -278,7 +272,6 @@ func New(config Config, chain BlockChain) *LegacyPool {
|
|||||||
reorgDoneCh: make(chan chan struct{}),
|
reorgDoneCh: make(chan chan struct{}),
|
||||||
reorgShutdownCh: make(chan struct{}),
|
reorgShutdownCh: make(chan struct{}),
|
||||||
initDoneCh: make(chan struct{}),
|
initDoneCh: make(chan struct{}),
|
||||||
localBufferPool: NewTxOverflowPoolHeap(config.OverflowPoolSlots),
|
|
||||||
}
|
}
|
||||||
pool.locals = newAccountSet(pool.signer)
|
pool.locals = newAccountSet(pool.signer)
|
||||||
for _, addr := range config.Locals {
|
for _, addr := range config.Locals {
|
||||||
@@ -415,6 +408,7 @@ func (pool *LegacyPool) loop() {
|
|||||||
if !pool.locals.contains(addr) {
|
if !pool.locals.contains(addr) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, tx := range list.Flatten() {
|
for _, tx := range list.Flatten() {
|
||||||
// Default ReannounceTime is 10 years, won't announce by default.
|
// Default ReannounceTime is 10 years, won't announce by default.
|
||||||
if time.Since(tx.Time()) < pool.config.ReannounceTime {
|
if time.Since(tx.Time()) < pool.config.ReannounceTime {
|
||||||
@@ -523,17 +517,6 @@ func (pool *LegacyPool) Stats() (int, int) {
|
|||||||
return pool.stats()
|
return pool.stats()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (pool *LegacyPool) statsOverflowPool() int {
|
|
||||||
pool.mu.RLock()
|
|
||||||
defer pool.mu.RUnlock()
|
|
||||||
|
|
||||||
if pool.localBufferPool == nil {
|
|
||||||
return 0
|
|
||||||
}
|
|
||||||
|
|
||||||
return pool.localBufferPool.Size()
|
|
||||||
}
|
|
||||||
|
|
||||||
// stats retrieves the current pool stats, namely the number of pending and the
|
// stats retrieves the current pool stats, namely the number of pending and the
|
||||||
// number of queued (non-executable) transactions.
|
// number of queued (non-executable) transactions.
|
||||||
func (pool *LegacyPool) stats() (int, int) {
|
func (pool *LegacyPool) stats() (int, int) {
|
||||||
@@ -848,8 +831,6 @@ func (pool *LegacyPool) add(tx *types.Transaction, local bool) (replaced bool, e
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pool.addToOverflowPool(drop, isLocal)
|
|
||||||
|
|
||||||
// Kick out the underpriced remote transactions.
|
// Kick out the underpriced remote transactions.
|
||||||
for _, tx := range drop {
|
for _, tx := range drop {
|
||||||
log.Trace("Discarding freshly underpriced transaction", "hash", tx.Hash(), "gasTipCap", tx.GasTipCap(), "gasFeeCap", tx.GasFeeCap())
|
log.Trace("Discarding freshly underpriced transaction", "hash", tx.Hash(), "gasTipCap", tx.GasTipCap(), "gasFeeCap", tx.GasFeeCap())
|
||||||
@@ -906,29 +887,6 @@ func (pool *LegacyPool) add(tx *types.Transaction, local bool) (replaced bool, e
|
|||||||
return replaced, nil
|
return replaced, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (pool *LegacyPool) addToOverflowPool(drop types.Transactions, isLocal bool) {
|
|
||||||
// calculate total number of slots in drop. Accordingly add them to OverflowPool (if there is space)
|
|
||||||
availableSlotsOverflowPool := pool.availableSlotsOverflowPool()
|
|
||||||
if availableSlotsOverflowPool > 0 {
|
|
||||||
// transfer availableSlotsOverflowPool number of transactions slots from drop to OverflowPool
|
|
||||||
currentSlotsUsed := 0
|
|
||||||
for i, tx := range drop {
|
|
||||||
txSlots := numSlots(tx)
|
|
||||||
if currentSlotsUsed+txSlots <= availableSlotsOverflowPool {
|
|
||||||
from, _ := types.Sender(pool.signer, tx)
|
|
||||||
pool.localBufferPool.Add(tx)
|
|
||||||
log.Debug("adding to OverflowPool", "transaction", tx.Hash().String(), "from", from.String())
|
|
||||||
currentSlotsUsed += txSlots
|
|
||||||
} else {
|
|
||||||
log.Debug("not all got added to OverflowPool", "totalAdded", i+1)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
log.Debug("adding to OverflowPool unsuccessful", "availableSlotsOverflowPool", availableSlotsOverflowPool)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// isGapped reports whether the given transaction is immediately executable.
|
// isGapped reports whether the given transaction is immediately executable.
|
||||||
func (pool *LegacyPool) isGapped(from common.Address, tx *types.Transaction) bool {
|
func (pool *LegacyPool) isGapped(from common.Address, tx *types.Transaction) bool {
|
||||||
// Short circuit if transaction falls within the scope of the pending list
|
// Short circuit if transaction falls within the scope of the pending list
|
||||||
@@ -1375,6 +1333,7 @@ func (pool *LegacyPool) runReorg(done chan struct{}, reset *txpoolResetRequest,
|
|||||||
reorgDurationTimer.Update(time.Since(t0))
|
reorgDurationTimer.Update(time.Since(t0))
|
||||||
}(time.Now())
|
}(time.Now())
|
||||||
defer close(done)
|
defer close(done)
|
||||||
|
|
||||||
var promoteAddrs []common.Address
|
var promoteAddrs []common.Address
|
||||||
if dirtyAccounts != nil && reset == nil {
|
if dirtyAccounts != nil && reset == nil {
|
||||||
// Only dirty accounts need to be promoted, unless we're resetting.
|
// Only dirty accounts need to be promoted, unless we're resetting.
|
||||||
@@ -1432,9 +1391,6 @@ func (pool *LegacyPool) runReorg(done chan struct{}, reset *txpoolResetRequest,
|
|||||||
pool.changesSinceReorg = 0 // Reset change counter
|
pool.changesSinceReorg = 0 // Reset change counter
|
||||||
pool.mu.Unlock()
|
pool.mu.Unlock()
|
||||||
|
|
||||||
// Transfer transactions from OverflowPool to MainPool for new block import
|
|
||||||
pool.transferTransactions()
|
|
||||||
|
|
||||||
// Notify subsystems for newly added transactions
|
// Notify subsystems for newly added transactions
|
||||||
for _, tx := range promoted {
|
for _, tx := range promoted {
|
||||||
addr, _ := types.Sender(pool.signer, tx)
|
addr, _ := types.Sender(pool.signer, tx)
|
||||||
@@ -2082,50 +2038,3 @@ func (t *lookup) RemotesBelowTip(threshold *big.Int) types.Transactions {
|
|||||||
func numSlots(tx *types.Transaction) int {
|
func numSlots(tx *types.Transaction) int {
|
||||||
return int((tx.Size() + txSlotSize - 1) / txSlotSize)
|
return int((tx.Size() + txSlotSize - 1) / txSlotSize)
|
||||||
}
|
}
|
||||||
|
|
||||||
// transferTransactions moves transactions from OverflowPool to MainPool
|
|
||||||
func (pool *LegacyPool) transferTransactions() {
|
|
||||||
// Fail fast if the overflow pool is empty
|
|
||||||
if pool.localBufferPool.Size() == 0 {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
maxMainPoolSize := int(pool.config.GlobalSlots + pool.config.GlobalQueue)
|
|
||||||
// Use pool.all.Slots() to get the total slots used by all transactions
|
|
||||||
currentMainPoolSize := pool.all.Slots()
|
|
||||||
if currentMainPoolSize >= maxMainPoolSize {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
extraSlots := maxMainPoolSize - currentMainPoolSize
|
|
||||||
extraTransactions := (extraSlots + 3) / 4 // Since a transaction can take up to 4 slots
|
|
||||||
log.Debug("Will attempt to transfer from OverflowPool to MainPool", "transactions", extraTransactions)
|
|
||||||
txs := pool.localBufferPool.Flush(extraTransactions)
|
|
||||||
if len(txs) == 0 {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
pool.Add(txs, true, false)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (pool *LegacyPool) availableSlotsOverflowPool() int {
|
|
||||||
maxOverflowPoolSize := int(pool.config.OverflowPoolSlots)
|
|
||||||
availableSlots := maxOverflowPoolSize - pool.localBufferPool.Size()
|
|
||||||
if availableSlots > 0 {
|
|
||||||
return availableSlots
|
|
||||||
}
|
|
||||||
return 0
|
|
||||||
}
|
|
||||||
|
|
||||||
func (pool *LegacyPool) PrintTxStats() {
|
|
||||||
for _, l := range pool.pending {
|
|
||||||
for _, transaction := range l.txs.items {
|
|
||||||
from, _ := types.Sender(pool.signer, transaction)
|
|
||||||
fmt.Println("from: ", from, " Pending:", transaction.Hash().String(), transaction.GasFeeCap(), transaction.GasTipCap())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pool.localBufferPool.PrintTxStats()
|
|
||||||
fmt.Println("length of all: ", pool.all.Slots())
|
|
||||||
fmt.Println("----------------------------------------------------")
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -40,7 +40,6 @@ import (
|
|||||||
"github.com/ethereum/go-ethereum/params"
|
"github.com/ethereum/go-ethereum/params"
|
||||||
"github.com/ethereum/go-ethereum/trie"
|
"github.com/ethereum/go-ethereum/trie"
|
||||||
"github.com/holiman/uint256"
|
"github.com/holiman/uint256"
|
||||||
"github.com/stretchr/testify/assert"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
@@ -1740,7 +1739,6 @@ func TestRepricingKeepsLocals(t *testing.T) {
|
|||||||
// Note, local transactions are never allowed to be dropped.
|
// Note, local transactions are never allowed to be dropped.
|
||||||
func TestUnderpricing(t *testing.T) {
|
func TestUnderpricing(t *testing.T) {
|
||||||
t.Parallel()
|
t.Parallel()
|
||||||
testTxPoolConfig.OverflowPoolSlots = 5
|
|
||||||
|
|
||||||
// Create the pool to test the pricing enforcement with
|
// Create the pool to test the pricing enforcement with
|
||||||
statedb, _ := state.New(types.EmptyRootHash, state.NewDatabase(rawdb.NewMemoryDatabase()), nil)
|
statedb, _ := state.New(types.EmptyRootHash, state.NewDatabase(rawdb.NewMemoryDatabase()), nil)
|
||||||
@@ -1933,8 +1931,6 @@ func TestUnderpricingDynamicFee(t *testing.T) {
|
|||||||
pool.config.GlobalSlots = 2
|
pool.config.GlobalSlots = 2
|
||||||
pool.config.GlobalQueue = 2
|
pool.config.GlobalQueue = 2
|
||||||
|
|
||||||
pool.config.OverflowPoolSlots = 0
|
|
||||||
|
|
||||||
// Keep track of transaction events to ensure all executables get announced
|
// Keep track of transaction events to ensure all executables get announced
|
||||||
events := make(chan core.NewTxsEvent, 32)
|
events := make(chan core.NewTxsEvent, 32)
|
||||||
sub := pool.txFeed.Subscribe(events)
|
sub := pool.txFeed.Subscribe(events)
|
||||||
@@ -1959,6 +1955,7 @@ func TestUnderpricingDynamicFee(t *testing.T) {
|
|||||||
// Import the batch and that both pending and queued transactions match up
|
// Import the batch and that both pending and queued transactions match up
|
||||||
pool.addRemotes(txs) // Pend K0:0, K0:1; Que K1:1
|
pool.addRemotes(txs) // Pend K0:0, K0:1; Que K1:1
|
||||||
pool.addLocal(ltx) // +K2:0 => Pend K0:0, K0:1, K2:0; Que K1:1
|
pool.addLocal(ltx) // +K2:0 => Pend K0:0, K0:1, K2:0; Que K1:1
|
||||||
|
|
||||||
pending, queued := pool.Stats()
|
pending, queued := pool.Stats()
|
||||||
if pending != 3 {
|
if pending != 3 {
|
||||||
t.Fatalf("pending transactions mismatched: have %d, want %d", pending, 3)
|
t.Fatalf("pending transactions mismatched: have %d, want %d", pending, 3)
|
||||||
@@ -1998,9 +1995,9 @@ func TestUnderpricingDynamicFee(t *testing.T) {
|
|||||||
t.Fatalf("pending transactions mismatched: have %d, want %d", pending, 2)
|
t.Fatalf("pending transactions mismatched: have %d, want %d", pending, 2)
|
||||||
}
|
}
|
||||||
if queued != 2 {
|
if queued != 2 {
|
||||||
t.Fatalf("queued transactions mismatched: have %d, want %d", queued, 1)
|
t.Fatalf("queued transactions mismatched: have %d, want %d", queued, 2)
|
||||||
}
|
}
|
||||||
if err := validateEvents(events, 2); err != nil { // todo make it 4...After this validateEvents the pending becomes 3?!
|
if err := validateEvents(events, 2); err != nil {
|
||||||
t.Fatalf("additional event firing failed: %v", err)
|
t.Fatalf("additional event firing failed: %v", err)
|
||||||
}
|
}
|
||||||
if err := validatePoolInternals(pool); err != nil {
|
if err := validatePoolInternals(pool); err != nil {
|
||||||
@@ -2015,12 +2012,11 @@ func TestUnderpricingDynamicFee(t *testing.T) {
|
|||||||
if err := pool.addLocal(ltx); err != nil {
|
if err := pool.addLocal(ltx); err != nil {
|
||||||
t.Fatalf("failed to add new underpriced local transaction: %v", err)
|
t.Fatalf("failed to add new underpriced local transaction: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
pending, queued = pool.Stats()
|
pending, queued = pool.Stats()
|
||||||
if pending != 3 { // 3
|
if pending != 3 {
|
||||||
t.Fatalf("pending transactions mismatched: have %d, want %d", pending, 3)
|
t.Fatalf("pending transactions mismatched: have %d, want %d", pending, 3)
|
||||||
}
|
}
|
||||||
if queued != 1 { // 1
|
if queued != 1 {
|
||||||
t.Fatalf("queued transactions mismatched: have %d, want %d", queued, 1)
|
t.Fatalf("queued transactions mismatched: have %d, want %d", queued, 1)
|
||||||
}
|
}
|
||||||
if err := validateEvents(events, 2); err != nil {
|
if err := validateEvents(events, 2); err != nil {
|
||||||
@@ -2036,51 +2032,41 @@ func TestUnderpricingDynamicFee(t *testing.T) {
|
|||||||
func TestDualHeapEviction(t *testing.T) {
|
func TestDualHeapEviction(t *testing.T) {
|
||||||
t.Parallel()
|
t.Parallel()
|
||||||
|
|
||||||
testTxPoolConfig.OverflowPoolSlots = 1
|
|
||||||
pool, _ := setupPoolWithConfig(eip1559Config)
|
pool, _ := setupPoolWithConfig(eip1559Config)
|
||||||
defer pool.Close()
|
defer pool.Close()
|
||||||
|
|
||||||
pool.config.GlobalSlots = 2
|
pool.config.GlobalSlots = 10
|
||||||
pool.config.GlobalQueue = 2
|
pool.config.GlobalQueue = 10
|
||||||
pool.config.OverflowPoolSlots = 1
|
|
||||||
|
|
||||||
var (
|
var (
|
||||||
highTip, highCap *types.Transaction
|
highTip, highCap *types.Transaction
|
||||||
baseFee int
|
baseFee int
|
||||||
highCapValue int64
|
|
||||||
highTipValue int64
|
|
||||||
)
|
)
|
||||||
|
|
||||||
check := func(tx *types.Transaction, name string) {
|
check := func(tx *types.Transaction, name string) {
|
||||||
if pool.all.GetRemote(tx.Hash()) == nil {
|
if pool.all.GetRemote(tx.Hash()) == nil {
|
||||||
t.Fatalf("highest %s transaction evicted from the pool, gasTip: %s, gasFeeCap: %s, hash: %s", name, highTip.GasTipCap().String(), highCap.GasFeeCap().String(), tx.Hash().String())
|
t.Fatalf("highest %s transaction evicted from the pool", name)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
add := func(urgent bool) {
|
add := func(urgent bool) {
|
||||||
for i := 0; i < 4; i++ {
|
for i := 0; i < 20; i++ {
|
||||||
var tx *types.Transaction
|
var tx *types.Transaction
|
||||||
// Create a test accounts and fund it
|
// Create a test accounts and fund it
|
||||||
key, _ := crypto.GenerateKey()
|
key, _ := crypto.GenerateKey()
|
||||||
testAddBalance(pool, crypto.PubkeyToAddress(key.PublicKey), big.NewInt(1000000000000))
|
testAddBalance(pool, crypto.PubkeyToAddress(key.PublicKey), big.NewInt(1000000000000))
|
||||||
if urgent {
|
if urgent {
|
||||||
tx = dynamicFeeTx(0, 100000, big.NewInt(int64(baseFee+1+i)), big.NewInt(int64(1+i)), key)
|
tx = dynamicFeeTx(0, 100000, big.NewInt(int64(baseFee+1+i)), big.NewInt(int64(1+i)), key)
|
||||||
if int64(1+i) > highTipValue || (int64(1+i) == highTipValue && int64(baseFee+1+i) > highTip.GasFeeCap().Int64()) {
|
|
||||||
highTipValue = int64(1 + i)
|
|
||||||
highTip = tx
|
highTip = tx
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
tx = dynamicFeeTx(0, 100000, big.NewInt(int64(baseFee+200+i)), big.NewInt(1), key)
|
tx = dynamicFeeTx(0, 100000, big.NewInt(int64(baseFee+200+i)), big.NewInt(1), key)
|
||||||
if int64(baseFee+200+i) > highCapValue {
|
|
||||||
highCapValue = int64(baseFee + 200 + i)
|
|
||||||
highCap = tx
|
highCap = tx
|
||||||
}
|
}
|
||||||
}
|
|
||||||
pool.addRemotesSync([]*types.Transaction{tx})
|
pool.addRemotesSync([]*types.Transaction{tx})
|
||||||
}
|
}
|
||||||
pending, queued := pool.Stats()
|
pending, queued := pool.Stats()
|
||||||
if pending+queued != 4 {
|
if pending+queued != 20 {
|
||||||
t.Fatalf("transaction count mismatch: have %d, want %d, pending %d, queued %d, OverflowPool %d", pending+queued, 5, pending, queued, pool.localBufferPool.Size())
|
t.Fatalf("transaction count mismatch: have %d, want %d", pending+queued, 10)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2245,50 +2231,6 @@ func TestReplacement(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestTransferTransactions(t *testing.T) {
|
|
||||||
t.Parallel()
|
|
||||||
testTxPoolConfig.OverflowPoolSlots = 1
|
|
||||||
pool, _ := setupPoolWithConfig(eip1559Config)
|
|
||||||
defer pool.Close()
|
|
||||||
|
|
||||||
pool.config.GlobalSlots = 1
|
|
||||||
pool.config.GlobalQueue = 2
|
|
||||||
|
|
||||||
// Create a number of test accounts and fund them
|
|
||||||
keys := make([]*ecdsa.PrivateKey, 5)
|
|
||||||
for i := 0; i < len(keys); i++ {
|
|
||||||
keys[i], _ = crypto.GenerateKey()
|
|
||||||
testAddBalance(pool, crypto.PubkeyToAddress(keys[i].PublicKey), big.NewInt(1000000))
|
|
||||||
}
|
|
||||||
|
|
||||||
tx := dynamicFeeTx(0, 100000, big.NewInt(3), big.NewInt(2), keys[0])
|
|
||||||
from, _ := types.Sender(pool.signer, tx)
|
|
||||||
pool.addToOverflowPool([]*types.Transaction{tx}, true)
|
|
||||||
pending, queue := pool.Stats()
|
|
||||||
|
|
||||||
assert.Equal(t, 0, pending, "pending transactions mismatched")
|
|
||||||
assert.Equal(t, 0, queue, "queued transactions mismatched")
|
|
||||||
assert.Equal(t, 1, pool.statsOverflowPool(), "OverflowPool size unexpected")
|
|
||||||
|
|
||||||
tx2 := dynamicFeeTx(0, 100000, big.NewInt(3), big.NewInt(2), keys[1])
|
|
||||||
pool.addToOverflowPool([]*types.Transaction{tx2}, true)
|
|
||||||
assert.Equal(t, 1, pool.statsOverflowPool(), "OverflowPool size unexpected")
|
|
||||||
<-pool.requestPromoteExecutables(newAccountSet(pool.signer, from))
|
|
||||||
pending, queue = pool.Stats()
|
|
||||||
|
|
||||||
assert.Equal(t, 0, pending, "pending transactions mismatched")
|
|
||||||
assert.Equal(t, 1, queue, "queued transactions mismatched")
|
|
||||||
assert.Equal(t, 0, pool.statsOverflowPool(), "OverflowPool size unexpected")
|
|
||||||
|
|
||||||
tx3 := dynamicFeeTx(0, 100000, big.NewInt(3), big.NewInt(2), keys[2])
|
|
||||||
pool.addToOverflowPool([]*types.Transaction{tx3}, true)
|
|
||||||
pending, queue = pool.Stats()
|
|
||||||
|
|
||||||
assert.Equal(t, 1, pending, "pending transactions mismatched")
|
|
||||||
assert.Equal(t, 0, queue, "queued transactions mismatched")
|
|
||||||
assert.Equal(t, 1, pool.statsOverflowPool(), "OverflowPool size unexpected")
|
|
||||||
}
|
|
||||||
|
|
||||||
// Tests that the pool rejects replacement dynamic fee transactions that don't
|
// Tests that the pool rejects replacement dynamic fee transactions that don't
|
||||||
// meet the minimum price bump required.
|
// meet the minimum price bump required.
|
||||||
func TestReplacementDynamicFee(t *testing.T) {
|
func TestReplacementDynamicFee(t *testing.T) {
|
||||||
|
|||||||
@@ -1,171 +0,0 @@
|
|||||||
package legacypool
|
|
||||||
|
|
||||||
import (
|
|
||||||
"container/heap"
|
|
||||||
"fmt"
|
|
||||||
"sync"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum/common"
|
|
||||||
"github.com/ethereum/go-ethereum/core/types"
|
|
||||||
)
|
|
||||||
|
|
||||||
// txHeapItem implements the Interface interface (https://pkg.go.dev/container/heap#Interface) of heap so that it can be heapified
|
|
||||||
type txHeapItem struct {
|
|
||||||
tx *types.Transaction
|
|
||||||
timestamp int64 // Unix timestamp (nanoseconds) of when the transaction was added
|
|
||||||
index int
|
|
||||||
}
|
|
||||||
|
|
||||||
type txHeap []*txHeapItem
|
|
||||||
|
|
||||||
func (h txHeap) Len() int { return len(h) }
|
|
||||||
func (h txHeap) Less(i, j int) bool {
|
|
||||||
return h[i].timestamp < h[j].timestamp
|
|
||||||
}
|
|
||||||
func (h txHeap) Swap(i, j int) {
|
|
||||||
if i < 0 || j < 0 || i >= len(h) || j >= len(h) {
|
|
||||||
return // Silently fail if indices are out of bounds
|
|
||||||
}
|
|
||||||
h[i], h[j] = h[j], h[i]
|
|
||||||
if h[i] != nil {
|
|
||||||
h[i].index = i
|
|
||||||
}
|
|
||||||
if h[j] != nil {
|
|
||||||
h[j].index = j
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (h *txHeap) Push(x interface{}) {
|
|
||||||
item, ok := x.(*txHeapItem)
|
|
||||||
if !ok {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
n := len(*h)
|
|
||||||
item.index = n
|
|
||||||
*h = append(*h, item)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (h *txHeap) Pop() interface{} {
|
|
||||||
old := *h
|
|
||||||
n := len(old)
|
|
||||||
if n == 0 {
|
|
||||||
return nil // Return nil if the heap is empty
|
|
||||||
}
|
|
||||||
item := old[n-1]
|
|
||||||
old[n-1] = nil // avoid memory leak
|
|
||||||
*h = old[0 : n-1]
|
|
||||||
if item != nil {
|
|
||||||
item.index = -1 // for safety
|
|
||||||
}
|
|
||||||
return item
|
|
||||||
}
|
|
||||||
|
|
||||||
type TxOverflowPool struct {
|
|
||||||
txHeap txHeap
|
|
||||||
index map[common.Hash]*txHeapItem
|
|
||||||
mu sync.RWMutex
|
|
||||||
maxSize uint64
|
|
||||||
totalSize int
|
|
||||||
}
|
|
||||||
|
|
||||||
func NewTxOverflowPoolHeap(estimatedMaxSize uint64) *TxOverflowPool {
|
|
||||||
return &TxOverflowPool{
|
|
||||||
txHeap: make(txHeap, 0, estimatedMaxSize),
|
|
||||||
index: make(map[common.Hash]*txHeapItem, estimatedMaxSize),
|
|
||||||
maxSize: estimatedMaxSize,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (tp *TxOverflowPool) Add(tx *types.Transaction) {
|
|
||||||
tp.mu.Lock()
|
|
||||||
defer tp.mu.Unlock()
|
|
||||||
|
|
||||||
if _, exists := tp.index[tx.Hash()]; exists {
|
|
||||||
// Transaction already in pool, ignore
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
if uint64(len(tp.txHeap)) >= tp.maxSize {
|
|
||||||
// Remove the oldest transaction to make space
|
|
||||||
oldestItem, ok := heap.Pop(&tp.txHeap).(*txHeapItem)
|
|
||||||
if !ok || oldestItem == nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
delete(tp.index, oldestItem.tx.Hash())
|
|
||||||
tp.totalSize -= numSlots(oldestItem.tx)
|
|
||||||
OverflowPoolGauge.Dec(1)
|
|
||||||
}
|
|
||||||
|
|
||||||
item := &txHeapItem{
|
|
||||||
tx: tx,
|
|
||||||
timestamp: time.Now().UnixNano(),
|
|
||||||
}
|
|
||||||
heap.Push(&tp.txHeap, item)
|
|
||||||
tp.index[tx.Hash()] = item
|
|
||||||
tp.totalSize += numSlots(tx)
|
|
||||||
OverflowPoolGauge.Inc(1)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (tp *TxOverflowPool) Get(hash common.Hash) (*types.Transaction, bool) {
|
|
||||||
tp.mu.RLock()
|
|
||||||
defer tp.mu.RUnlock()
|
|
||||||
if item, ok := tp.index[hash]; ok {
|
|
||||||
return item.tx, true
|
|
||||||
}
|
|
||||||
return nil, false
|
|
||||||
}
|
|
||||||
|
|
||||||
func (tp *TxOverflowPool) Remove(hash common.Hash) {
|
|
||||||
tp.mu.Lock()
|
|
||||||
defer tp.mu.Unlock()
|
|
||||||
if item, ok := tp.index[hash]; ok {
|
|
||||||
heap.Remove(&tp.txHeap, item.index)
|
|
||||||
delete(tp.index, hash)
|
|
||||||
tp.totalSize -= numSlots(item.tx)
|
|
||||||
OverflowPoolGauge.Dec(1)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (tp *TxOverflowPool) Flush(n int) []*types.Transaction {
|
|
||||||
tp.mu.Lock()
|
|
||||||
defer tp.mu.Unlock()
|
|
||||||
if n > tp.txHeap.Len() {
|
|
||||||
n = tp.txHeap.Len()
|
|
||||||
}
|
|
||||||
txs := make([]*types.Transaction, n)
|
|
||||||
for i := 0; i < n; i++ {
|
|
||||||
item, ok := heap.Pop(&tp.txHeap).(*txHeapItem)
|
|
||||||
if !ok || item == nil {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
txs[i] = item.tx
|
|
||||||
delete(tp.index, item.tx.Hash())
|
|
||||||
tp.totalSize -= numSlots(item.tx)
|
|
||||||
}
|
|
||||||
|
|
||||||
OverflowPoolGauge.Dec(int64(n))
|
|
||||||
return txs
|
|
||||||
}
|
|
||||||
|
|
||||||
func (tp *TxOverflowPool) Len() int {
|
|
||||||
tp.mu.RLock()
|
|
||||||
defer tp.mu.RUnlock()
|
|
||||||
return tp.txHeap.Len()
|
|
||||||
}
|
|
||||||
|
|
||||||
func (tp *TxOverflowPool) Size() int {
|
|
||||||
tp.mu.RLock()
|
|
||||||
defer tp.mu.RUnlock()
|
|
||||||
return tp.totalSize
|
|
||||||
}
|
|
||||||
|
|
||||||
func (tp *TxOverflowPool) PrintTxStats() {
|
|
||||||
tp.mu.RLock()
|
|
||||||
defer tp.mu.RUnlock()
|
|
||||||
for _, item := range tp.txHeap {
|
|
||||||
tx := item.tx
|
|
||||||
fmt.Printf("Hash: %s, Timestamp: %d, GasFeeCap: %s, GasTipCap: %s\n",
|
|
||||||
tx.Hash().String(), item.timestamp, tx.GasFeeCap().String(), tx.GasTipCap().String())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,266 +0,0 @@
|
|||||||
package legacypool
|
|
||||||
|
|
||||||
import (
|
|
||||||
"math/big"
|
|
||||||
rand2 "math/rand"
|
|
||||||
"testing"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/cometbft/cometbft/libs/rand"
|
|
||||||
"github.com/ethereum/go-ethereum/common"
|
|
||||||
"github.com/ethereum/go-ethereum/core/types"
|
|
||||||
)
|
|
||||||
|
|
||||||
// Helper function to create a test transaction
|
|
||||||
func createTestTx(nonce uint64, gasPrice *big.Int) *types.Transaction {
|
|
||||||
to := common.HexToAddress("0x1234567890123456789012345678901234567890")
|
|
||||||
return types.NewTransaction(nonce, to, big.NewInt(1000), 21000, gasPrice, nil)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestNewTxOverflowPoolHeap(t *testing.T) {
|
|
||||||
pool := NewTxOverflowPoolHeap(0)
|
|
||||||
if pool == nil {
|
|
||||||
t.Fatal("NewTxOverflowPoolHeap returned nil")
|
|
||||||
}
|
|
||||||
if pool.Len() != 0 {
|
|
||||||
t.Errorf("New pool should be empty, got length %d", pool.Len())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestTxOverflowPoolHeapAdd(t *testing.T) {
|
|
||||||
pool := NewTxOverflowPoolHeap(1)
|
|
||||||
tx := createTestTx(1, big.NewInt(1000))
|
|
||||||
|
|
||||||
pool.Add(tx)
|
|
||||||
if pool.Len() != 1 {
|
|
||||||
t.Errorf("Pool should have 1 transaction, got %d", pool.Len())
|
|
||||||
}
|
|
||||||
|
|
||||||
// Add the same transaction again
|
|
||||||
pool.Add(tx)
|
|
||||||
if pool.Len() != 1 {
|
|
||||||
t.Errorf("Pool should still have 1 transaction after adding duplicate, got %d", pool.Len())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestTxOverflowPoolHeapGet(t *testing.T) {
|
|
||||||
pool := NewTxOverflowPoolHeap(1)
|
|
||||||
tx := createTestTx(1, big.NewInt(1000))
|
|
||||||
pool.Add(tx)
|
|
||||||
|
|
||||||
gotTx, exists := pool.Get(tx.Hash())
|
|
||||||
if !exists {
|
|
||||||
t.Fatal("Get returned false for existing transaction")
|
|
||||||
}
|
|
||||||
if gotTx.Hash() != tx.Hash() {
|
|
||||||
t.Errorf("Get returned wrong transaction. Want %v, got %v", tx.Hash(), gotTx.Hash())
|
|
||||||
}
|
|
||||||
|
|
||||||
_, exists = pool.Get(common.Hash{})
|
|
||||||
if exists {
|
|
||||||
t.Error("Get returned true for non-existent transaction")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestTxOverflowPoolHeapRemove(t *testing.T) {
|
|
||||||
pool := NewTxOverflowPoolHeap(1)
|
|
||||||
tx := createTestTx(1, big.NewInt(1000))
|
|
||||||
pool.Add(tx)
|
|
||||||
|
|
||||||
pool.Remove(tx.Hash())
|
|
||||||
if pool.Len() != 0 {
|
|
||||||
t.Errorf("Pool should be empty after removing the only transaction, got length %d", pool.Len())
|
|
||||||
}
|
|
||||||
|
|
||||||
// Try to remove non-existent transaction
|
|
||||||
pool.Remove(common.Hash{})
|
|
||||||
if pool.Len() != 0 {
|
|
||||||
t.Error("Removing non-existent transaction should not affect pool size")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestTxOverflowPoolHeapPopN(t *testing.T) {
|
|
||||||
pool := NewTxOverflowPoolHeap(3)
|
|
||||||
tx1 := createTestTx(1, big.NewInt(1000))
|
|
||||||
tx2 := createTestTx(2, big.NewInt(2000))
|
|
||||||
tx3 := createTestTx(3, big.NewInt(3000))
|
|
||||||
|
|
||||||
pool.Add(tx1)
|
|
||||||
time.Sleep(time.Millisecond) // Ensure different timestamps
|
|
||||||
pool.Add(tx2)
|
|
||||||
time.Sleep(time.Millisecond)
|
|
||||||
pool.Add(tx3)
|
|
||||||
|
|
||||||
popped := pool.Flush(2)
|
|
||||||
if len(popped) != 2 {
|
|
||||||
t.Fatalf("PopN(2) should return 2 transactions, got %d", len(popped))
|
|
||||||
}
|
|
||||||
if popped[0].Hash() != tx1.Hash() || popped[1].Hash() != tx2.Hash() {
|
|
||||||
t.Error("PopN returned transactions in wrong order")
|
|
||||||
}
|
|
||||||
if pool.Len() != 1 {
|
|
||||||
t.Errorf("Pool should have 1 transaction left, got %d", pool.Len())
|
|
||||||
}
|
|
||||||
|
|
||||||
// Pop more than available
|
|
||||||
popped = pool.Flush(2)
|
|
||||||
if len(popped) != 1 {
|
|
||||||
t.Fatalf("PopN(2) should return 1 transaction when only 1 is left, got %d", len(popped))
|
|
||||||
}
|
|
||||||
if popped[0].Hash() != tx3.Hash() {
|
|
||||||
t.Error("PopN returned wrong transaction")
|
|
||||||
}
|
|
||||||
if pool.Len() != 0 {
|
|
||||||
t.Errorf("Pool should be empty, got length %d", pool.Len())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestTxOverflowPoolHeapOrdering(t *testing.T) {
|
|
||||||
pool := NewTxOverflowPoolHeap(3)
|
|
||||||
tx1 := createTestTx(1, big.NewInt(1000))
|
|
||||||
tx2 := createTestTx(2, big.NewInt(2000))
|
|
||||||
tx3 := createTestTx(3, big.NewInt(3000))
|
|
||||||
|
|
||||||
pool.Add(tx2)
|
|
||||||
time.Sleep(time.Millisecond) // Ensure different timestamps
|
|
||||||
pool.Add(tx1)
|
|
||||||
pool.Add(tx3) // Added immediately after tx1, should have same timestamp but higher sequence
|
|
||||||
|
|
||||||
popped := pool.Flush(3)
|
|
||||||
if len(popped) != 3 {
|
|
||||||
t.Fatalf("PopN(3) should return 3 transactions, got %d", len(popped))
|
|
||||||
}
|
|
||||||
if popped[0].Hash() != tx2.Hash() || popped[1].Hash() != tx1.Hash() || popped[2].Hash() != tx3.Hash() {
|
|
||||||
t.Error("Transactions not popped in correct order (earliest timestamp first, then by sequence)")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestTxOverflowPoolHeapLen(t *testing.T) {
|
|
||||||
pool := NewTxOverflowPoolHeap(2)
|
|
||||||
if pool.Len() != 0 {
|
|
||||||
t.Errorf("New pool should have length 0, got %d", pool.Len())
|
|
||||||
}
|
|
||||||
|
|
||||||
pool.Add(createTestTx(1, big.NewInt(1000)))
|
|
||||||
if pool.Len() != 1 {
|
|
||||||
t.Errorf("Pool should have length 1 after adding a transaction, got %d", pool.Len())
|
|
||||||
}
|
|
||||||
|
|
||||||
pool.Add(createTestTx(2, big.NewInt(2000)))
|
|
||||||
if pool.Len() != 2 {
|
|
||||||
t.Errorf("Pool should have length 2 after adding another transaction, got %d", pool.Len())
|
|
||||||
}
|
|
||||||
|
|
||||||
pool.Flush(1)
|
|
||||||
if pool.Len() != 1 {
|
|
||||||
t.Errorf("Pool should have length 1 after popping a transaction, got %d", pool.Len())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Helper function to create a random test transaction
|
|
||||||
func createRandomTestTx() *types.Transaction {
|
|
||||||
nonce := uint64(rand.Intn(1000000))
|
|
||||||
to := common.BytesToAddress(rand.Bytes(20))
|
|
||||||
amount := new(big.Int).Rand(rand2.New(rand2.NewSource(rand.Int63())), big.NewInt(1e18))
|
|
||||||
gasLimit := uint64(21000)
|
|
||||||
gasPrice := new(big.Int).Rand(rand2.New(rand2.NewSource(rand.Int63())), big.NewInt(1e9))
|
|
||||||
data := rand.Bytes(100)
|
|
||||||
return types.NewTransaction(nonce, to, amount, gasLimit, gasPrice, data)
|
|
||||||
}
|
|
||||||
|
|
||||||
func createRandomTestTxs(n int) []*types.Transaction {
|
|
||||||
txs := make([]*types.Transaction, n)
|
|
||||||
for i := 0; i < n; i++ {
|
|
||||||
txs[i] = createRandomTestTx()
|
|
||||||
}
|
|
||||||
return txs
|
|
||||||
}
|
|
||||||
|
|
||||||
// goos: darwin
|
|
||||||
// goarch: arm64
|
|
||||||
// pkg: github.com/ethereum/go-ethereum/core/txpool/legacypool
|
|
||||||
// BenchmarkTxOverflowPoolHeapAdd-8 813326 2858 ns/op
|
|
||||||
func BenchmarkTxOverflowPoolHeapAdd(b *testing.B) {
|
|
||||||
pool := NewTxOverflowPoolHeap(uint64(b.N))
|
|
||||||
txs := createRandomTestTxs(b.N)
|
|
||||||
b.ResetTimer()
|
|
||||||
for i := 0; i < b.N; i++ {
|
|
||||||
pool.Add(txs[i])
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// BenchmarkTxOverflowPoolHeapGet-8 32613938 35.63 ns/op
|
|
||||||
func BenchmarkTxOverflowPoolHeapGet(b *testing.B) {
|
|
||||||
pool := NewTxOverflowPoolHeap(1000)
|
|
||||||
txs := createRandomTestTxs(1000)
|
|
||||||
for _, tx := range txs {
|
|
||||||
pool.Add(tx)
|
|
||||||
}
|
|
||||||
b.ResetTimer()
|
|
||||||
for i := 0; i < b.N; i++ {
|
|
||||||
pool.Get(txs[i%1000].Hash())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// BenchmarkTxOverflowPoolHeapRemove-8 3020841 417.8 ns/op
|
|
||||||
func BenchmarkTxOverflowPoolHeapRemove(b *testing.B) {
|
|
||||||
pool := NewTxOverflowPoolHeap(uint64(b.N))
|
|
||||||
txs := createRandomTestTxs(b.N)
|
|
||||||
for _, tx := range txs {
|
|
||||||
pool.Add(tx)
|
|
||||||
}
|
|
||||||
b.ResetTimer()
|
|
||||||
for i := 0; i < b.N; i++ {
|
|
||||||
pool.Remove(txs[i].Hash())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// BenchmarkTxOverflowPoolHeapFlush-8 42963656 29.90 ns/op
|
|
||||||
func BenchmarkTxOverflowPoolHeapFlush(b *testing.B) {
|
|
||||||
pool := NewTxOverflowPoolHeap(1000)
|
|
||||||
txs := createRandomTestTxs(1000)
|
|
||||||
for _, tx := range txs {
|
|
||||||
pool.Add(tx)
|
|
||||||
}
|
|
||||||
b.ResetTimer()
|
|
||||||
for i := 0; i < b.N; i++ {
|
|
||||||
pool.Flush(10)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// BenchmarkTxOverflowPoolHeapLen-8 79147188 20.07 ns/op
|
|
||||||
func BenchmarkTxOverflowPoolHeapLen(b *testing.B) {
|
|
||||||
pool := NewTxOverflowPoolHeap(1000)
|
|
||||||
txs := createRandomTestTxs(1000)
|
|
||||||
for _, tx := range txs {
|
|
||||||
pool.Add(tx)
|
|
||||||
}
|
|
||||||
b.ResetTimer()
|
|
||||||
for i := 0; i < b.N; i++ {
|
|
||||||
pool.Len()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// BenchmarkTxOverflowPoolHeapAddRemove-8 902896 1546 ns/op
|
|
||||||
func BenchmarkTxOverflowPoolHeapAddRemove(b *testing.B) {
|
|
||||||
pool := NewTxOverflowPoolHeap(uint64(b.N))
|
|
||||||
txs := createRandomTestTxs(b.N)
|
|
||||||
b.ResetTimer()
|
|
||||||
for i := 0; i < b.N; i++ {
|
|
||||||
pool.Add(txs[i])
|
|
||||||
pool.Remove(txs[i].Hash())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// BenchmarkTxOverflowPoolHeapAddFlush-8 84417 14899 ns/op
|
|
||||||
func BenchmarkTxOverflowPoolHeapAddFlush(b *testing.B) {
|
|
||||||
pool := NewTxOverflowPoolHeap(uint64(b.N * 10))
|
|
||||||
txs := createRandomTestTxs(b.N * 10)
|
|
||||||
b.ResetTimer()
|
|
||||||
for i := 0; i < b.N; i++ {
|
|
||||||
for j := 0; j < 10; j++ {
|
|
||||||
pool.Add(txs[i*10+j])
|
|
||||||
}
|
|
||||||
pool.Flush(10)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,43 +0,0 @@
|
|||||||
package types
|
|
||||||
|
|
||||||
import (
|
|
||||||
"encoding/json"
|
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum/common"
|
|
||||||
"github.com/ethereum/go-ethereum/common/hexutil"
|
|
||||||
)
|
|
||||||
|
|
||||||
type AccountStorage struct {
|
|
||||||
StorageRoot *common.Hash
|
|
||||||
StorageSlots map[common.Hash]common.Hash
|
|
||||||
}
|
|
||||||
|
|
||||||
func (a *AccountStorage) UnmarshalJSON(data []byte) error {
|
|
||||||
var hash common.Hash
|
|
||||||
if err := json.Unmarshal(data, &hash); err == nil {
|
|
||||||
a.StorageRoot = &hash
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
return json.Unmarshal(data, &a.StorageSlots)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (a AccountStorage) MarshalJSON() ([]byte, error) {
|
|
||||||
if a.StorageRoot != nil {
|
|
||||||
return json.Marshal(*a.StorageRoot)
|
|
||||||
}
|
|
||||||
return json.Marshal(a.StorageSlots)
|
|
||||||
}
|
|
||||||
|
|
||||||
type KnownAccounts map[common.Address]AccountStorage
|
|
||||||
|
|
||||||
// It is known that marshaling is broken
|
|
||||||
// https://github.com/golang/go/issues/55890
|
|
||||||
|
|
||||||
//go:generate go run github.com/fjl/gencodec -type TransactionOpts -out gen_tx_opts_json.go
|
|
||||||
type TransactionOpts struct {
|
|
||||||
KnownAccounts KnownAccounts `json:"knownAccounts"`
|
|
||||||
BlockNumberMin *hexutil.Uint64 `json:"blockNumberMin,omitempty"`
|
|
||||||
BlockNumberMax *hexutil.Uint64 `json:"blockNumberMax,omitempty"`
|
|
||||||
TimestampMin *hexutil.Uint64 `json:"timestampMin,omitempty"`
|
|
||||||
TimestampMax *hexutil.Uint64 `json:"timestampMax,omitempty"`
|
|
||||||
}
|
|
||||||
@@ -29,6 +29,7 @@ import (
|
|||||||
"github.com/ethereum/go-ethereum/common/hexutil"
|
"github.com/ethereum/go-ethereum/common/hexutil"
|
||||||
"github.com/ethereum/go-ethereum/core"
|
"github.com/ethereum/go-ethereum/core"
|
||||||
"github.com/ethereum/go-ethereum/core/types"
|
"github.com/ethereum/go-ethereum/core/types"
|
||||||
|
"github.com/ethereum/go-ethereum/internal/ethapi"
|
||||||
"github.com/ethereum/go-ethereum/rpc"
|
"github.com/ethereum/go-ethereum/rpc"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -736,7 +737,7 @@ func (ec *Client) SendTransaction(ctx context.Context, tx *types.Transaction) er
|
|||||||
//
|
//
|
||||||
// If the transaction was a contract creation use the TransactionReceipt method to get the
|
// If the transaction was a contract creation use the TransactionReceipt method to get the
|
||||||
// contract address after the transaction has been mined.
|
// contract address after the transaction has been mined.
|
||||||
func (ec *Client) SendTransactionConditional(ctx context.Context, tx *types.Transaction, opts types.TransactionOpts) error {
|
func (ec *Client) SendTransactionConditional(ctx context.Context, tx *types.Transaction, opts ethapi.TransactionOpts) error {
|
||||||
data, err := tx.MarshalBinary()
|
data, err := tx.MarshalBinary()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
|||||||
@@ -34,6 +34,7 @@ import (
|
|||||||
"github.com/ethereum/go-ethereum/crypto"
|
"github.com/ethereum/go-ethereum/crypto"
|
||||||
"github.com/ethereum/go-ethereum/eth"
|
"github.com/ethereum/go-ethereum/eth"
|
||||||
"github.com/ethereum/go-ethereum/eth/ethconfig"
|
"github.com/ethereum/go-ethereum/eth/ethconfig"
|
||||||
|
"github.com/ethereum/go-ethereum/internal/ethapi"
|
||||||
"github.com/ethereum/go-ethereum/node"
|
"github.com/ethereum/go-ethereum/node"
|
||||||
"github.com/ethereum/go-ethereum/params"
|
"github.com/ethereum/go-ethereum/params"
|
||||||
"github.com/ethereum/go-ethereum/rlp"
|
"github.com/ethereum/go-ethereum/rlp"
|
||||||
@@ -769,9 +770,9 @@ func sendTransactionConditional(ec *Client) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
root := common.HexToHash("0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421")
|
root := common.HexToHash("0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421")
|
||||||
return ec.SendTransactionConditional(context.Background(), tx, types.TransactionOpts{
|
return ec.SendTransactionConditional(context.Background(), tx, ethapi.TransactionOpts{
|
||||||
KnownAccounts: map[common.Address]types.AccountStorage{
|
KnownAccounts: map[common.Address]ethapi.AccountStorage{
|
||||||
testAddr: types.AccountStorage{
|
testAddr: ethapi.AccountStorage{
|
||||||
StorageRoot: &root,
|
StorageRoot: &root,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -30,6 +30,7 @@ import (
|
|||||||
"github.com/ethereum/go-ethereum/eth/ethconfig"
|
"github.com/ethereum/go-ethereum/eth/ethconfig"
|
||||||
"github.com/ethereum/go-ethereum/eth/filters"
|
"github.com/ethereum/go-ethereum/eth/filters"
|
||||||
"github.com/ethereum/go-ethereum/ethclient"
|
"github.com/ethereum/go-ethereum/ethclient"
|
||||||
|
"github.com/ethereum/go-ethereum/internal/ethapi"
|
||||||
"github.com/ethereum/go-ethereum/node"
|
"github.com/ethereum/go-ethereum/node"
|
||||||
"github.com/ethereum/go-ethereum/p2p"
|
"github.com/ethereum/go-ethereum/p2p"
|
||||||
"github.com/ethereum/go-ethereum/params"
|
"github.com/ethereum/go-ethereum/params"
|
||||||
@@ -38,7 +39,7 @@ import (
|
|||||||
|
|
||||||
// TransactionConditionalSender injects the conditional transaction into the pending pool for execution after verification.
|
// TransactionConditionalSender injects the conditional transaction into the pending pool for execution after verification.
|
||||||
type TransactionConditionalSender interface {
|
type TransactionConditionalSender interface {
|
||||||
SendTransactionConditional(ctx context.Context, tx *types.Transaction, opts types.TransactionOpts) error
|
SendTransactionConditional(ctx context.Context, tx *types.Transaction, opts ethapi.TransactionOpts) error
|
||||||
}
|
}
|
||||||
|
|
||||||
// Client exposes the methods provided by the Ethereum RPC client.
|
// Client exposes the methods provided by the Ethereum RPC client.
|
||||||
|
|||||||
@@ -2314,7 +2314,7 @@ func (s *TransactionAPI) SendRawTransaction(ctx context.Context, input hexutil.B
|
|||||||
|
|
||||||
// SendRawTransactionConditional will add the signed transaction to the transaction pool.
|
// SendRawTransactionConditional will add the signed transaction to the transaction pool.
|
||||||
// The sender/bundler is responsible for signing the transaction
|
// The sender/bundler is responsible for signing the transaction
|
||||||
func (s *TransactionAPI) SendRawTransactionConditional(ctx context.Context, input hexutil.Bytes, opts types.TransactionOpts) (common.Hash, error) {
|
func (s *TransactionAPI) SendRawTransactionConditional(ctx context.Context, input hexutil.Bytes, opts TransactionOpts) (common.Hash, error) {
|
||||||
tx := new(types.Transaction)
|
tx := new(types.Transaction)
|
||||||
if err := tx.UnmarshalBinary(input); err != nil {
|
if err := tx.UnmarshalBinary(input); err != nil {
|
||||||
return common.Hash{}, err
|
return common.Hash{}, err
|
||||||
@@ -2324,7 +2324,7 @@ func (s *TransactionAPI) SendRawTransactionConditional(ctx context.Context, inpu
|
|||||||
if state == nil || err != nil {
|
if state == nil || err != nil {
|
||||||
return common.Hash{}, err
|
return common.Hash{}, err
|
||||||
}
|
}
|
||||||
if err := TxOptsCheck(opts, header.Number.Uint64(), header.Time, state); err != nil {
|
if err := opts.Check(header.Number.Uint64(), header.Time, state); err != nil {
|
||||||
return common.Hash{}, err
|
return common.Hash{}, err
|
||||||
}
|
}
|
||||||
return SubmitTransaction(ctx, s.b, tx)
|
return SubmitTransaction(ctx, s.b, tx)
|
||||||
|
|||||||
@@ -1,9 +1,10 @@
|
|||||||
// Code generated by github.com/fjl/gencodec. DO NOT EDIT.
|
// Code generated by github.com/fjl/gencodec. DO NOT EDIT.
|
||||||
|
|
||||||
package types
|
package ethapi
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum/common/hexutil"
|
"github.com/ethereum/go-ethereum/common/hexutil"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -2,15 +2,52 @@ package ethapi
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
|
"encoding/json"
|
||||||
"errors"
|
"errors"
|
||||||
|
|
||||||
|
"github.com/ethereum/go-ethereum/common"
|
||||||
|
"github.com/ethereum/go-ethereum/common/hexutil"
|
||||||
"github.com/ethereum/go-ethereum/core/state"
|
"github.com/ethereum/go-ethereum/core/state"
|
||||||
"github.com/ethereum/go-ethereum/core/types"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
|
type AccountStorage struct {
|
||||||
|
StorageRoot *common.Hash
|
||||||
|
StorageSlots map[common.Hash]common.Hash
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *AccountStorage) UnmarshalJSON(data []byte) error {
|
||||||
|
var hash common.Hash
|
||||||
|
if err := json.Unmarshal(data, &hash); err == nil {
|
||||||
|
a.StorageRoot = &hash
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return json.Unmarshal(data, &a.StorageSlots)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a AccountStorage) MarshalJSON() ([]byte, error) {
|
||||||
|
if a.StorageRoot != nil {
|
||||||
|
return json.Marshal(*a.StorageRoot)
|
||||||
|
}
|
||||||
|
return json.Marshal(a.StorageSlots)
|
||||||
|
}
|
||||||
|
|
||||||
|
type KnownAccounts map[common.Address]AccountStorage
|
||||||
|
|
||||||
|
// It is known that marshaling is broken
|
||||||
|
// https://github.com/golang/go/issues/55890
|
||||||
|
|
||||||
|
//go:generate go run github.com/fjl/gencodec -type TransactionOpts -out gen_tx_opts_json.go
|
||||||
|
type TransactionOpts struct {
|
||||||
|
KnownAccounts KnownAccounts `json:"knownAccounts"`
|
||||||
|
BlockNumberMin *hexutil.Uint64 `json:"blockNumberMin,omitempty"`
|
||||||
|
BlockNumberMax *hexutil.Uint64 `json:"blockNumberMax,omitempty"`
|
||||||
|
TimestampMin *hexutil.Uint64 `json:"timestampMin,omitempty"`
|
||||||
|
TimestampMax *hexutil.Uint64 `json:"timestampMax,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
const MaxNumberOfEntries = 1000
|
const MaxNumberOfEntries = 1000
|
||||||
|
|
||||||
func TxOptsCheck(o types.TransactionOpts, blockNumber uint64, timeStamp uint64, statedb *state.StateDB) error {
|
func (o *TransactionOpts) Check(blockNumber uint64, timeStamp uint64, statedb *state.StateDB) error {
|
||||||
if o.BlockNumberMin != nil && blockNumber < uint64(*o.BlockNumberMin) {
|
if o.BlockNumberMin != nil && blockNumber < uint64(*o.BlockNumberMin) {
|
||||||
return errors.New("BlockNumberMin condition not met")
|
return errors.New("BlockNumberMin condition not met")
|
||||||
}
|
}
|
||||||
@@ -34,10 +71,10 @@ func TxOptsCheck(o types.TransactionOpts, blockNumber uint64, timeStamp uint64,
|
|||||||
if counter > MaxNumberOfEntries {
|
if counter > MaxNumberOfEntries {
|
||||||
return errors.New("knownAccounts too large")
|
return errors.New("knownAccounts too large")
|
||||||
}
|
}
|
||||||
return TxOptsCheckStorage(o, statedb)
|
return o.CheckStorage(statedb)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TxOptsCheckStorage(o types.TransactionOpts, statedb *state.StateDB) error {
|
func (o *TransactionOpts) CheckStorage(statedb *state.StateDB) error {
|
||||||
for address, accountStorage := range o.KnownAccounts {
|
for address, accountStorage := range o.KnownAccounts {
|
||||||
if accountStorage.StorageRoot != nil {
|
if accountStorage.StorageRoot != nil {
|
||||||
rootHash := statedb.GetRoot(address)
|
rootHash := statedb.GetRoot(address)
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package types
|
package ethapi_test
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
@@ -7,6 +7,7 @@ import (
|
|||||||
|
|
||||||
"github.com/ethereum/go-ethereum/common"
|
"github.com/ethereum/go-ethereum/common"
|
||||||
"github.com/ethereum/go-ethereum/common/hexutil"
|
"github.com/ethereum/go-ethereum/common/hexutil"
|
||||||
|
"github.com/ethereum/go-ethereum/internal/ethapi"
|
||||||
)
|
)
|
||||||
|
|
||||||
func ptr(hash common.Hash) *common.Hash {
|
func ptr(hash common.Hash) *common.Hash {
|
||||||
@@ -22,15 +23,15 @@ func TestTransactionOptsJSONUnMarshalTrip(t *testing.T) {
|
|||||||
name string
|
name string
|
||||||
input string
|
input string
|
||||||
mustFail bool
|
mustFail bool
|
||||||
expected TransactionOpts
|
expected ethapi.TransactionOpts
|
||||||
}{
|
}{
|
||||||
{
|
{
|
||||||
"StateRoot",
|
"StateRoot",
|
||||||
`{"knownAccounts":{"0x6b3A8798E5Fb9fC5603F3aB5eA2e8136694e55d0":"0x290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e563"}}`,
|
`{"knownAccounts":{"0x6b3A8798E5Fb9fC5603F3aB5eA2e8136694e55d0":"0x290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e563"}}`,
|
||||||
false,
|
false,
|
||||||
TransactionOpts{
|
ethapi.TransactionOpts{
|
||||||
KnownAccounts: map[common.Address]AccountStorage{
|
KnownAccounts: map[common.Address]ethapi.AccountStorage{
|
||||||
common.HexToAddress("0x6b3A8798E5Fb9fC5603F3aB5eA2e8136694e55d0"): AccountStorage{
|
common.HexToAddress("0x6b3A8798E5Fb9fC5603F3aB5eA2e8136694e55d0"): ethapi.AccountStorage{
|
||||||
StorageRoot: ptr(common.HexToHash("0x290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e563")),
|
StorageRoot: ptr(common.HexToHash("0x290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e563")),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@@ -40,9 +41,9 @@ func TestTransactionOptsJSONUnMarshalTrip(t *testing.T) {
|
|||||||
"StorageSlots",
|
"StorageSlots",
|
||||||
`{"knownAccounts":{"0x6b3A8798E5Fb9fC5603F3aB5eA2e8136694e55d0":{"0xc65a7bb8d6351c1cf70c95a316cc6a92839c986682d98bc35f958f4883f9d2a8":"0x0000000000000000000000000000000000000000000000000000000000000000"}}}`,
|
`{"knownAccounts":{"0x6b3A8798E5Fb9fC5603F3aB5eA2e8136694e55d0":{"0xc65a7bb8d6351c1cf70c95a316cc6a92839c986682d98bc35f958f4883f9d2a8":"0x0000000000000000000000000000000000000000000000000000000000000000"}}}`,
|
||||||
false,
|
false,
|
||||||
TransactionOpts{
|
ethapi.TransactionOpts{
|
||||||
KnownAccounts: map[common.Address]AccountStorage{
|
KnownAccounts: map[common.Address]ethapi.AccountStorage{
|
||||||
common.HexToAddress("0x6b3A8798E5Fb9fC5603F3aB5eA2e8136694e55d0"): AccountStorage{
|
common.HexToAddress("0x6b3A8798E5Fb9fC5603F3aB5eA2e8136694e55d0"): ethapi.AccountStorage{
|
||||||
StorageRoot: nil,
|
StorageRoot: nil,
|
||||||
StorageSlots: map[common.Hash]common.Hash{
|
StorageSlots: map[common.Hash]common.Hash{
|
||||||
common.HexToHash("0xc65a7bb8d6351c1cf70c95a316cc6a92839c986682d98bc35f958f4883f9d2a8"): common.HexToHash("0x"),
|
common.HexToHash("0xc65a7bb8d6351c1cf70c95a316cc6a92839c986682d98bc35f958f4883f9d2a8"): common.HexToHash("0x"),
|
||||||
@@ -55,15 +56,15 @@ func TestTransactionOptsJSONUnMarshalTrip(t *testing.T) {
|
|||||||
"EmptyObject",
|
"EmptyObject",
|
||||||
`{"knownAccounts":{}}`,
|
`{"knownAccounts":{}}`,
|
||||||
false,
|
false,
|
||||||
TransactionOpts{
|
ethapi.TransactionOpts{
|
||||||
KnownAccounts: make(map[common.Address]AccountStorage),
|
KnownAccounts: make(map[common.Address]ethapi.AccountStorage),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"EmptyStrings",
|
"EmptyStrings",
|
||||||
`{"knownAccounts":{"":""}}`,
|
`{"knownAccounts":{"":""}}`,
|
||||||
true,
|
true,
|
||||||
TransactionOpts{
|
ethapi.TransactionOpts{
|
||||||
KnownAccounts: nil,
|
KnownAccounts: nil,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@@ -71,7 +72,7 @@ func TestTransactionOptsJSONUnMarshalTrip(t *testing.T) {
|
|||||||
"BlockNumberMin",
|
"BlockNumberMin",
|
||||||
`{"blockNumberMin":"0x1"}`,
|
`{"blockNumberMin":"0x1"}`,
|
||||||
false,
|
false,
|
||||||
TransactionOpts{
|
ethapi.TransactionOpts{
|
||||||
BlockNumberMin: u64Ptr(1),
|
BlockNumberMin: u64Ptr(1),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@@ -79,7 +80,7 @@ func TestTransactionOptsJSONUnMarshalTrip(t *testing.T) {
|
|||||||
"BlockNumberMax",
|
"BlockNumberMax",
|
||||||
`{"blockNumberMin":"0x1", "blockNumberMax":"0x2"}`,
|
`{"blockNumberMin":"0x1", "blockNumberMax":"0x2"}`,
|
||||||
false,
|
false,
|
||||||
TransactionOpts{
|
ethapi.TransactionOpts{
|
||||||
BlockNumberMin: u64Ptr(1),
|
BlockNumberMin: u64Ptr(1),
|
||||||
BlockNumberMax: u64Ptr(2),
|
BlockNumberMax: u64Ptr(2),
|
||||||
},
|
},
|
||||||
@@ -88,7 +89,7 @@ func TestTransactionOptsJSONUnMarshalTrip(t *testing.T) {
|
|||||||
"TimestampMin",
|
"TimestampMin",
|
||||||
`{"timestampMin":"0xffff"}`,
|
`{"timestampMin":"0xffff"}`,
|
||||||
false,
|
false,
|
||||||
TransactionOpts{
|
ethapi.TransactionOpts{
|
||||||
TimestampMin: u64Ptr(0xffff),
|
TimestampMin: u64Ptr(0xffff),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@@ -96,7 +97,7 @@ func TestTransactionOptsJSONUnMarshalTrip(t *testing.T) {
|
|||||||
"TimestampMax",
|
"TimestampMax",
|
||||||
`{"timestampMax":"0xffffff"}`,
|
`{"timestampMax":"0xffffff"}`,
|
||||||
false,
|
false,
|
||||||
TransactionOpts{
|
ethapi.TransactionOpts{
|
||||||
TimestampMax: u64Ptr(0xffffff),
|
TimestampMax: u64Ptr(0xffffff),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@@ -104,7 +105,7 @@ func TestTransactionOptsJSONUnMarshalTrip(t *testing.T) {
|
|||||||
|
|
||||||
for _, test := range tests {
|
for _, test := range tests {
|
||||||
t.Run(test.name, func(t *testing.T) {
|
t.Run(test.name, func(t *testing.T) {
|
||||||
var opts TransactionOpts
|
var opts ethapi.TransactionOpts
|
||||||
err := json.Unmarshal([]byte(test.input), &opts)
|
err := json.Unmarshal([]byte(test.input), &opts)
|
||||||
if test.mustFail && err == nil {
|
if test.mustFail && err == nil {
|
||||||
t.Errorf("Test %s should fail", test.name)
|
t.Errorf("Test %s should fail", test.name)
|
||||||
Reference in New Issue
Block a user