mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-08-20 10:52:25 +00:00
accounts/abi/backends: change SimulatedBackend to interface
This commit is contained in:
parent
cb549c9455
commit
71eec44d7b
2 changed files with 84 additions and 25 deletions
|
|
@ -19,8 +19,12 @@ package backends
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"math"
|
"math"
|
||||||
|
"math/big"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/ethereum/go-ethereum"
|
||||||
"github.com/ethereum/go-ethereum/accounts/abi/bind"
|
"github.com/ethereum/go-ethereum/accounts/abi/bind"
|
||||||
|
"github.com/ethereum/go-ethereum/common"
|
||||||
"github.com/ethereum/go-ethereum/core"
|
"github.com/ethereum/go-ethereum/core"
|
||||||
"github.com/ethereum/go-ethereum/eth"
|
"github.com/ethereum/go-ethereum/eth"
|
||||||
"github.com/ethereum/go-ethereum/eth/catalyst"
|
"github.com/ethereum/go-ethereum/eth/catalyst"
|
||||||
|
|
@ -34,9 +38,51 @@ import (
|
||||||
"github.com/ethereum/go-ethereum/rpc"
|
"github.com/ethereum/go-ethereum/rpc"
|
||||||
)
|
)
|
||||||
|
|
||||||
var _ bind.ContractBackend = (*SimulatedBackend)(nil)
|
var _ bind.ContractBackend = (*simBackend)(nil)
|
||||||
|
|
||||||
type SimulatedBackend struct {
|
type SimChainManagement interface {
|
||||||
|
// Commit seals a block and moves the chain forward to a new empty block.
|
||||||
|
Commit() common.Hash
|
||||||
|
|
||||||
|
// Rollback un-sends previously added transactions.
|
||||||
|
Rollback()
|
||||||
|
|
||||||
|
// Fork sets the head to a new block, which is based on the provided parentHash.
|
||||||
|
Fork(ctx context.Context, parentHash common.Hash) error
|
||||||
|
|
||||||
|
// AdjustTime changes the block timestamp.
|
||||||
|
AdjustTime(adjustment time.Duration) error
|
||||||
|
|
||||||
|
// Close closes the backend. You need to call this to clean up resources.
|
||||||
|
Close() error
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: these methods should have their own interface in the ethereum package.
|
||||||
|
type SimChainExtras interface {
|
||||||
|
BlockNumber(context.Context) (uint64, error)
|
||||||
|
ChainID(context.Context) (*big.Int, error)
|
||||||
|
}
|
||||||
|
|
||||||
|
// SimulatedBackend all interfaces in the ethereum package, but is based on a
|
||||||
|
// simulated blockchain. It is intended for testing purposes.
|
||||||
|
type SimulatedBackend interface {
|
||||||
|
SimChainManagement
|
||||||
|
|
||||||
|
// The backend implements all interfaces in the ethereum package.
|
||||||
|
ethereum.ChainReader
|
||||||
|
ethereum.ChainStateReader
|
||||||
|
ethereum.ContractCaller
|
||||||
|
ethereum.GasEstimator
|
||||||
|
ethereum.LogFilterer
|
||||||
|
ethereum.GasPricer
|
||||||
|
ethereum.PendingStateReader
|
||||||
|
ethereum.PendingContractCaller
|
||||||
|
ethereum.TransactionReader
|
||||||
|
ethereum.TransactionSender
|
||||||
|
SimChainExtras
|
||||||
|
}
|
||||||
|
|
||||||
|
type simBackend struct {
|
||||||
eth *eth.Ethereum
|
eth *eth.Ethereum
|
||||||
*catalyst.SimulatedBeacon
|
*catalyst.SimulatedBeacon
|
||||||
*ethclient.Client
|
*ethclient.Client
|
||||||
|
|
@ -45,7 +91,7 @@ type SimulatedBackend struct {
|
||||||
// NewSimulatedBackend creates a new binding backend using a simulated blockchain
|
// NewSimulatedBackend creates a new binding backend using a simulated blockchain
|
||||||
// for testing purposes.
|
// for testing purposes.
|
||||||
// A simulated backend always uses chainID 1337.
|
// A simulated backend always uses chainID 1337.
|
||||||
func NewSimulatedBackend(alloc core.GenesisAlloc, gasLimit uint64) *SimulatedBackend {
|
func NewSimulatedBackend(alloc core.GenesisAlloc, gasLimit uint64) SimulatedBackend {
|
||||||
// Setup the node object
|
// Setup the node object
|
||||||
nodeConf := node.DefaultConfig
|
nodeConf := node.DefaultConfig
|
||||||
nodeConf.DataDir = ""
|
nodeConf.DataDir = ""
|
||||||
|
|
@ -76,7 +122,7 @@ func NewSimulatedBackend(alloc core.GenesisAlloc, gasLimit uint64) *SimulatedBac
|
||||||
// NewSimWithNode sets up a simulated backend on an existing node
|
// NewSimWithNode sets up a simulated backend on an existing node
|
||||||
// this allows users to do persistent simulations.
|
// this allows users to do persistent simulations.
|
||||||
// The provided node must not be started and will be started by NewSimWithNode
|
// The provided node must not be started and will be started by NewSimWithNode
|
||||||
func NewSimWithNode(stack *node.Node, conf *eth.Config, blockPeriod uint64) (*SimulatedBackend, error) {
|
func NewSimWithNode(stack *node.Node, conf *eth.Config, blockPeriod uint64) (SimulatedBackend, error) {
|
||||||
backend, err := eth.New(stack, conf)
|
backend, err := eth.New(stack, conf)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
|
@ -105,14 +151,14 @@ func NewSimWithNode(stack *node.Node, conf *eth.Config, blockPeriod uint64) (*Si
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
return &SimulatedBackend{
|
return &simBackend{
|
||||||
eth: backend,
|
eth: backend,
|
||||||
SimulatedBeacon: beacon,
|
SimulatedBeacon: beacon,
|
||||||
Client: ethclient.NewClient(stack.Attach()),
|
Client: ethclient.NewClient(stack.Attach()),
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (n *SimulatedBackend) Close() error {
|
func (n *simBackend) Close() error {
|
||||||
if n.Client != nil {
|
if n.Client != nil {
|
||||||
n.Client.Close()
|
n.Client.Close()
|
||||||
n.Client = nil
|
n.Client = nil
|
||||||
|
|
|
||||||
|
|
@ -36,7 +36,7 @@ var (
|
||||||
testAddr = crypto.PubkeyToAddress(testKey.PublicKey)
|
testAddr = crypto.PubkeyToAddress(testKey.PublicKey)
|
||||||
)
|
)
|
||||||
|
|
||||||
func simTestBackend(testAddr common.Address) *SimulatedBackend {
|
func simTestBackend(testAddr common.Address) SimulatedBackend {
|
||||||
return NewSimulatedBackend(
|
return NewSimulatedBackend(
|
||||||
core.GenesisAlloc{
|
core.GenesisAlloc{
|
||||||
testAddr: {Balance: big.NewInt(10000000000000000)},
|
testAddr: {Balance: big.NewInt(10000000000000000)},
|
||||||
|
|
@ -44,12 +44,7 @@ func simTestBackend(testAddr common.Address) *SimulatedBackend {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (sim *SimulatedBackend) currentBlock() *types.Block {
|
func newTx(sim SimulatedBackend, key *ecdsa.PrivateKey) (*types.Transaction, error) {
|
||||||
current, _ := sim.BlockByNumber(context.Background(), nil)
|
|
||||||
return current
|
|
||||||
}
|
|
||||||
|
|
||||||
func (sim *SimulatedBackend) newTx(key *ecdsa.PrivateKey) (*types.Transaction, error) {
|
|
||||||
// create a signed transaction to send
|
// create a signed transaction to send
|
||||||
head, _ := sim.HeaderByNumber(context.Background(), nil) // Should be child's, good enough
|
head, _ := sim.HeaderByNumber(context.Background(), nil) // Should be child's, good enough
|
||||||
gasPrice := new(big.Int).Add(head.BaseFee, big.NewInt(1))
|
gasPrice := new(big.Int).Add(head.BaseFee, big.NewInt(1))
|
||||||
|
|
@ -113,7 +108,7 @@ func TestSendTransaction(t *testing.T) {
|
||||||
defer sim.Close()
|
defer sim.Close()
|
||||||
bgCtx := context.Background()
|
bgCtx := context.Background()
|
||||||
|
|
||||||
signedTx, err := sim.newTx(testKey)
|
signedTx, err := newTx(sim, testKey)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("could not create transaction: %v", err)
|
t.Errorf("could not create transaction: %v", err)
|
||||||
}
|
}
|
||||||
|
|
@ -148,25 +143,35 @@ func TestFork(t *testing.T) {
|
||||||
testAddr := crypto.PubkeyToAddress(testKey.PublicKey)
|
testAddr := crypto.PubkeyToAddress(testKey.PublicKey)
|
||||||
sim := simTestBackend(testAddr)
|
sim := simTestBackend(testAddr)
|
||||||
defer sim.Close()
|
defer sim.Close()
|
||||||
|
|
||||||
|
ctx := context.Background()
|
||||||
|
|
||||||
// 1.
|
// 1.
|
||||||
parent := sim.currentBlock()
|
parent, _ := sim.HeaderByNumber(ctx, nil)
|
||||||
|
|
||||||
// 2.
|
// 2.
|
||||||
n := int(rand.Int31n(21))
|
n := int(rand.Int31n(21))
|
||||||
for i := 0; i < n; i++ {
|
for i := 0; i < n; i++ {
|
||||||
sim.Commit()
|
sim.Commit()
|
||||||
}
|
}
|
||||||
|
|
||||||
// 3.
|
// 3.
|
||||||
if sim.currentBlock().Number().Uint64() != uint64(n) {
|
b, _ := sim.BlockNumber(ctx)
|
||||||
|
if b != uint64(n) {
|
||||||
t.Error("wrong chain length")
|
t.Error("wrong chain length")
|
||||||
}
|
}
|
||||||
|
|
||||||
// 4.
|
// 4.
|
||||||
sim.Fork(context.Background(), parent.Hash())
|
sim.Fork(ctx, parent.Hash())
|
||||||
|
|
||||||
// 5.
|
// 5.
|
||||||
for i := 0; i < n+1; i++ {
|
for i := 0; i < n+1; i++ {
|
||||||
sim.Commit()
|
sim.Commit()
|
||||||
}
|
}
|
||||||
|
|
||||||
// 6.
|
// 6.
|
||||||
if sim.currentBlock().Number().Uint64() != uint64(n+1) {
|
b, _ = sim.BlockNumber(ctx)
|
||||||
|
if b != uint64(n+1) {
|
||||||
t.Error("wrong chain length")
|
t.Error("wrong chain length")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -185,24 +190,30 @@ func TestForkResendTx(t *testing.T) {
|
||||||
testAddr := crypto.PubkeyToAddress(testKey.PublicKey)
|
testAddr := crypto.PubkeyToAddress(testKey.PublicKey)
|
||||||
sim := simTestBackend(testAddr)
|
sim := simTestBackend(testAddr)
|
||||||
defer sim.Close()
|
defer sim.Close()
|
||||||
|
|
||||||
// 1.
|
// 1.
|
||||||
parent := sim.currentBlock()
|
ctx := context.Background()
|
||||||
|
parent, _ := sim.HeaderByNumber(ctx, nil)
|
||||||
|
|
||||||
// 2.
|
// 2.
|
||||||
tx, err := sim.newTx(testKey)
|
tx, err := newTx(sim, testKey)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("could not create transaction: %v", err)
|
t.Fatalf("could not create transaction: %v", err)
|
||||||
}
|
}
|
||||||
sim.SendTransaction(context.Background(), tx)
|
sim.SendTransaction(context.Background(), tx)
|
||||||
sim.Commit()
|
sim.Commit()
|
||||||
|
|
||||||
// 3.
|
// 3.
|
||||||
receipt, _ := sim.TransactionReceipt(context.Background(), tx.Hash())
|
receipt, _ := sim.TransactionReceipt(context.Background(), tx.Hash())
|
||||||
if h := receipt.BlockNumber.Uint64(); h != 1 {
|
if h := receipt.BlockNumber.Uint64(); h != 1 {
|
||||||
t.Errorf("TX included in wrong block: %d", h)
|
t.Errorf("TX included in wrong block: %d", h)
|
||||||
}
|
}
|
||||||
|
|
||||||
// 4.
|
// 4.
|
||||||
if err := sim.Fork(context.Background(), parent.Hash()); err != nil {
|
if err := sim.Fork(context.Background(), parent.Hash()); err != nil {
|
||||||
t.Errorf("forking: %v", err)
|
t.Errorf("forking: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// 5.
|
// 5.
|
||||||
sim.Commit()
|
sim.Commit()
|
||||||
if err := sim.SendTransaction(context.Background(), tx); err != nil {
|
if err := sim.SendTransaction(context.Background(), tx); err != nil {
|
||||||
|
|
@ -223,7 +234,8 @@ func TestCommitReturnValue(t *testing.T) {
|
||||||
|
|
||||||
// Test if Commit returns the correct block hash
|
// Test if Commit returns the correct block hash
|
||||||
h1 := sim.Commit()
|
h1 := sim.Commit()
|
||||||
if h1 != sim.currentBlock().Hash() {
|
cur, _ := sim.HeaderByNumber(context.Background(), nil)
|
||||||
|
if h1 != cur.Hash() {
|
||||||
t.Error("Commit did not return the hash of the last block.")
|
t.Error("Commit did not return the hash of the last block.")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -262,14 +274,15 @@ func TestAdjustTimeAfterFork(t *testing.T) {
|
||||||
defer sim.Close()
|
defer sim.Close()
|
||||||
|
|
||||||
sim.Commit() // h1
|
sim.Commit() // h1
|
||||||
h1 := sim.currentBlock().Hash()
|
h1, _ := sim.HeaderByNumber(context.Background(), nil)
|
||||||
|
|
||||||
sim.Commit() // h2
|
sim.Commit() // h2
|
||||||
sim.Fork(context.Background(), h1)
|
sim.Fork(context.Background(), h1.Hash())
|
||||||
sim.AdjustTime(1 * time.Second)
|
sim.AdjustTime(1 * time.Second)
|
||||||
sim.Commit()
|
sim.Commit()
|
||||||
|
|
||||||
head := sim.currentBlock()
|
head, _ := sim.HeaderByNumber(context.Background(), nil)
|
||||||
if head.Number() == common.Big2 && head.ParentHash() != h1 {
|
if head.Number.Uint64() == 2 && head.ParentHash != h1.Hash() {
|
||||||
t.Errorf("failed to build block on fork")
|
t.Errorf("failed to build block on fork")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue