github.com/onflow/flow-go@v0.33.17/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/ethereum/go-ethereum/common"
    12  	gethTypes "github.com/ethereum/go-ethereum/core/types"
    13  	gethCrypto "github.com/ethereum/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) SetNonce(nonce uint64) {
   101  	a.lock.Lock()
   102  	defer a.lock.Unlock()
   103  
   104  	a.nonce = nonce
   105  }
   106  
   107  func GetTestEOAAccount(t testing.TB, keyHex string) *EOATestAccount {
   108  	key, _ := gethCrypto.HexToECDSA(keyHex)
   109  	address := gethCrypto.PubkeyToAddress(key.PublicKey)
   110  	signer := emulator.GetDefaultSigner()
   111  	return &EOATestAccount{
   112  		address: address,
   113  		key:     key,
   114  		signer:  signer,
   115  		lock:    sync.Mutex{},
   116  	}
   117  }
   118  
   119  func RunWithEOATestAccount(t testing.TB, led atree.Ledger, flowEVMRootAddress flow.Address, f func(*EOATestAccount)) {
   120  	account := FundAndGetEOATestAccount(t, led, flowEVMRootAddress)
   121  	f(account)
   122  }
   123  
   124  func FundAndGetEOATestAccount(t testing.TB, led atree.Ledger, flowEVMRootAddress flow.Address) *EOATestAccount {
   125  	account := GetTestEOAAccount(t, EOATestAccount1KeyHex)
   126  
   127  	// fund account
   128  	e := emulator.NewEmulator(led, flowEVMRootAddress)
   129  
   130  	blk, err := e.NewBlockView(types.NewDefaultBlockContext(2))
   131  	require.NoError(t, err)
   132  
   133  	_, err = blk.DirectCall(
   134  		types.NewDepositCall(
   135  			account.Address(),
   136  			new(big.Int).Mul(big.NewInt(1e18), big.NewInt(1000)),
   137  		),
   138  	)
   139  	require.NoError(t, err)
   140  
   141  	blk2, err := e.NewReadOnlyBlockView(types.NewDefaultBlockContext(2))
   142  	require.NoError(t, err)
   143  
   144  	bal, err := blk2.BalanceOf(account.Address())
   145  	require.NoError(t, err)
   146  	require.Greater(t, bal.Uint64(), uint64(0))
   147  
   148  	return account
   149  }