github.com/onflow/flow-go@v0.35.7-crescendo-preview.23-atree-inlining/fvm/evm/testutils/accounts.go (about)

     1  package testutils
     2  
     3  import (
     4  	"bytes"
     5  	"crypto/ecdsa"
     6  	"io"
     7  	"math/big"
     8  	"sync"
     9  	"testing"
    10  
    11  	gethCommon "github.com/onflow/go-ethereum/common"
    12  	gethTypes "github.com/onflow/go-ethereum/core/types"
    13  	gethCrypto "github.com/onflow/go-ethereum/crypto"
    14  	"github.com/stretchr/testify/require"
    15  
    16  	"github.com/onflow/atree"
    17  
    18  	"github.com/onflow/flow-go/fvm/evm/emulator"
    19  	"github.com/onflow/flow-go/fvm/evm/types"
    20  	"github.com/onflow/flow-go/model/flow"
    21  )
    22  
    23  // address:  658bdf435d810c91414ec09147daa6db62406379
    24  const EOATestAccount1KeyHex = "9c647b8b7c4e7c3490668fb6c11473619db80c93704c70893d3813af4090c39c"
    25  
    26  type EOATestAccount struct {
    27  	address gethCommon.Address
    28  	key     *ecdsa.PrivateKey
    29  	nonce   uint64
    30  	signer  gethTypes.Signer
    31  	lock    sync.Mutex
    32  }
    33  
    34  func (a *EOATestAccount) Address() types.Address {
    35  	return types.Address(a.address)
    36  }
    37  
    38  func (a *EOATestAccount) PrepareSignAndEncodeTx(
    39  	t testing.TB,
    40  	to gethCommon.Address,
    41  	data []byte,
    42  	amount *big.Int,
    43  	gasLimit uint64,
    44  	gasPrice *big.Int,
    45  ) []byte {
    46  	tx := a.PrepareAndSignTx(t, to, data, amount, gasLimit, gasPrice)
    47  	var b bytes.Buffer
    48  	writer := io.Writer(&b)
    49  	err := tx.EncodeRLP(writer)
    50  	require.NoError(t, err)
    51  	return b.Bytes()
    52  }
    53  
    54  func (a *EOATestAccount) PrepareAndSignTx(
    55  	t testing.TB,
    56  	to gethCommon.Address,
    57  	data []byte,
    58  	amount *big.Int,
    59  	gasLimit uint64,
    60  	gasPrice *big.Int,
    61  ) *gethTypes.Transaction {
    62  	a.lock.Lock()
    63  	defer a.lock.Unlock()
    64  
    65  	tx := a.signTx(
    66  		t,
    67  		gethTypes.NewTransaction(
    68  			a.nonce,
    69  			to,
    70  			amount,
    71  			gasLimit,
    72  			gasPrice,
    73  			data,
    74  		),
    75  	)
    76  	a.nonce++
    77  
    78  	return tx
    79  }
    80  
    81  func (a *EOATestAccount) SignTx(
    82  	t testing.TB,
    83  	tx *gethTypes.Transaction,
    84  ) *gethTypes.Transaction {
    85  	a.lock.Lock()
    86  	defer a.lock.Unlock()
    87  
    88  	return a.signTx(t, tx)
    89  }
    90  
    91  func (a *EOATestAccount) signTx(
    92  	t testing.TB,
    93  	tx *gethTypes.Transaction,
    94  ) *gethTypes.Transaction {
    95  	tx, err := gethTypes.SignTx(tx, a.signer, a.key)
    96  	require.NoError(t, err)
    97  	return tx
    98  }
    99  
   100  func (a *EOATestAccount) Nonce() uint64 {
   101  	return a.nonce
   102  }
   103  
   104  func (a *EOATestAccount) SetNonce(nonce uint64) {
   105  	a.lock.Lock()
   106  	defer a.lock.Unlock()
   107  
   108  	a.nonce = nonce
   109  }
   110  
   111  func GetTestEOAAccount(t testing.TB, keyHex string) *EOATestAccount {
   112  	key, _ := gethCrypto.HexToECDSA(keyHex)
   113  	address := gethCrypto.PubkeyToAddress(key.PublicKey)
   114  	signer := emulator.GetDefaultSigner()
   115  	return &EOATestAccount{
   116  		address: address,
   117  		key:     key,
   118  		signer:  signer,
   119  		lock:    sync.Mutex{},
   120  	}
   121  }
   122  
   123  func RunWithEOATestAccount(t testing.TB, led atree.Ledger, flowEVMRootAddress flow.Address, f func(*EOATestAccount)) {
   124  	account := FundAndGetEOATestAccount(t, led, flowEVMRootAddress)
   125  	f(account)
   126  }
   127  
   128  func FundAndGetEOATestAccount(t testing.TB, led atree.Ledger, flowEVMRootAddress flow.Address) *EOATestAccount {
   129  	account := GetTestEOAAccount(t, EOATestAccount1KeyHex)
   130  
   131  	// fund account
   132  	e := emulator.NewEmulator(led, flowEVMRootAddress)
   133  
   134  	blk, err := e.NewBlockView(types.NewDefaultBlockContext(2))
   135  	require.NoError(t, err)
   136  
   137  	_, err = blk.DirectCall(
   138  		types.NewDepositCall(
   139  			RandomAddress(t), // any random non-empty address works here
   140  			account.Address(),
   141  			new(big.Int).Mul(big.NewInt(1e18), big.NewInt(1000)),
   142  			account.nonce,
   143  		),
   144  	)
   145  	require.NoError(t, err)
   146  
   147  	blk2, err := e.NewReadOnlyBlockView(types.NewDefaultBlockContext(2))
   148  	require.NoError(t, err)
   149  
   150  	bal, err := blk2.BalanceOf(account.Address())
   151  	require.NoError(t, err)
   152  	require.Greater(t, bal.Uint64(), uint64(0))
   153  
   154  	return account
   155  }