github.com/ethersphere/bee/v2@v2.2.0/pkg/transaction/backendsimulation/backend.go (about)

     1  // Copyright 2021 The Swarm Authors. All rights reserved.
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  package backendsimulation
     6  
     7  import (
     8  	"context"
     9  	"errors"
    10  	"math/big"
    11  
    12  	"github.com/ethereum/go-ethereum"
    13  	"github.com/ethereum/go-ethereum/common"
    14  	"github.com/ethereum/go-ethereum/core/types"
    15  	"github.com/ethersphere/bee/v2/pkg/transaction"
    16  )
    17  
    18  type AccountAtKey struct {
    19  	BlockNumber uint64
    20  	Account     common.Address
    21  }
    22  
    23  type simulatedBackend struct {
    24  	blockNumber uint64
    25  
    26  	receipts map[common.Hash]*types.Receipt
    27  	noncesAt map[AccountAtKey]uint64
    28  
    29  	blocks []Block
    30  	step   uint64
    31  }
    32  
    33  type Block struct {
    34  	Number   uint64
    35  	Receipts map[common.Hash]*types.Receipt
    36  	NoncesAt map[AccountAtKey]uint64
    37  }
    38  
    39  type Option interface {
    40  	apply(*simulatedBackend)
    41  }
    42  
    43  type optionFunc func(*simulatedBackend)
    44  
    45  func (f optionFunc) apply(r *simulatedBackend) { f(r) }
    46  
    47  func WithBlocks(blocks ...Block) Option {
    48  	return optionFunc(func(sb *simulatedBackend) {
    49  		sb.blocks = blocks
    50  	})
    51  }
    52  
    53  func New(options ...Option) transaction.Backend {
    54  	m := &simulatedBackend{
    55  		receipts: make(map[common.Hash]*types.Receipt),
    56  		noncesAt: make(map[AccountAtKey]uint64),
    57  
    58  		blockNumber: 0,
    59  	}
    60  	for _, opt := range options {
    61  		opt.apply(m)
    62  	}
    63  
    64  	return m
    65  }
    66  
    67  func (m *simulatedBackend) advanceBlock() {
    68  	if m.step >= uint64(len(m.blocks)) {
    69  		return
    70  	}
    71  	block := m.blocks[m.step]
    72  	m.step++
    73  
    74  	m.blockNumber = block.Number
    75  
    76  	if block.Receipts != nil {
    77  		for hash, receipt := range block.Receipts {
    78  			m.receipts[hash] = receipt
    79  		}
    80  	}
    81  
    82  	if block.NoncesAt != nil {
    83  		for addr, nonce := range block.NoncesAt {
    84  			m.noncesAt[addr] = nonce
    85  		}
    86  	}
    87  }
    88  
    89  func (m *simulatedBackend) BlockByNumber(ctx context.Context, number *big.Int) (*types.Block, error) {
    90  	return nil, errors.New("not implemented")
    91  }
    92  
    93  func (m *simulatedBackend) CodeAt(ctx context.Context, contract common.Address, blockNumber *big.Int) ([]byte, error) {
    94  	return nil, errors.New("not implemented")
    95  }
    96  
    97  func (*simulatedBackend) CallContract(ctx context.Context, call ethereum.CallMsg, blockNumber *big.Int) ([]byte, error) {
    98  	return nil, errors.New("not implemented")
    99  }
   100  
   101  func (*simulatedBackend) PendingCodeAt(ctx context.Context, account common.Address) ([]byte, error) {
   102  	return nil, errors.New("not implemented")
   103  }
   104  
   105  func (m *simulatedBackend) PendingNonceAt(ctx context.Context, account common.Address) (uint64, error) {
   106  	return 0, errors.New("not implemented")
   107  }
   108  
   109  func (m *simulatedBackend) SuggestGasPrice(ctx context.Context) (*big.Int, error) {
   110  	return nil, errors.New("not implemented")
   111  }
   112  
   113  func (m *simulatedBackend) EstimateGas(ctx context.Context, call ethereum.CallMsg) (gas uint64, err error) {
   114  	return 0, errors.New("not implemented")
   115  }
   116  
   117  func (m *simulatedBackend) SendTransaction(ctx context.Context, tx *types.Transaction) error {
   118  	return errors.New("not implemented")
   119  }
   120  
   121  func (*simulatedBackend) FilterLogs(ctx context.Context, query ethereum.FilterQuery) ([]types.Log, error) {
   122  	return nil, errors.New("not implemented")
   123  }
   124  
   125  func (*simulatedBackend) SubscribeFilterLogs(ctx context.Context, query ethereum.FilterQuery, ch chan<- types.Log) (ethereum.Subscription, error) {
   126  	return nil, errors.New("not implemented")
   127  }
   128  
   129  func (m *simulatedBackend) TransactionReceipt(ctx context.Context, txHash common.Hash) (*types.Receipt, error) {
   130  	receipt, ok := m.receipts[txHash]
   131  	if ok {
   132  		return receipt, nil
   133  	} else {
   134  		return nil, ethereum.NotFound
   135  	}
   136  }
   137  
   138  func (m *simulatedBackend) TransactionByHash(ctx context.Context, hash common.Hash) (tx *types.Transaction, isPending bool, err error) {
   139  	return nil, false, errors.New("not implemented")
   140  }
   141  
   142  func (m *simulatedBackend) BlockNumber(ctx context.Context) (uint64, error) {
   143  	m.advanceBlock()
   144  	return m.blockNumber, nil
   145  }
   146  
   147  func (m *simulatedBackend) HeaderByNumber(ctx context.Context, number *big.Int) (*types.Header, error) {
   148  	return nil, errors.New("not implemented")
   149  }
   150  
   151  func (m *simulatedBackend) BalanceAt(ctx context.Context, address common.Address, block *big.Int) (*big.Int, error) {
   152  	return nil, errors.New("not implemented")
   153  }
   154  func (m *simulatedBackend) NonceAt(ctx context.Context, account common.Address, blockNumber *big.Int) (uint64, error) {
   155  	nonce, ok := m.noncesAt[AccountAtKey{Account: account, BlockNumber: blockNumber.Uint64()}]
   156  	if ok {
   157  		return nonce, nil
   158  	} else {
   159  		return 0, nil
   160  	}
   161  }
   162  
   163  func (m *simulatedBackend) SuggestGasTipCap(ctx context.Context) (*big.Int, error) {
   164  	return nil, errors.New("not implemented")
   165  }
   166  
   167  func (m *simulatedBackend) ChainID(ctx context.Context) (*big.Int, error) {
   168  	return nil, errors.New("not implemented")
   169  }
   170  
   171  func (m *simulatedBackend) Close() {
   172  }