owned this note
owned this note
Published
Linked with GitHub
# zkEvmChainTesting
## Prerequisites:
- a linux machine with docker engine installed
## Instructions:
### 1. Setup
```
cd into zkEvmChainTesting directory &
run setup.sh
```
### 2. Test execution
```
#docker exec --workdir /Code/TestCode -it gotest bash
#go run . -h to see the possible arguments
```
or
```
Navigate to zkEvmChainTesting/TestCode on host machine and run
./zkevmchaintest -h
If this is the prefered approach, in case of local code changes, rerun
#docker exec --workdir /Code/TestCode gotest go build .
```
---
## SIMULATOR CODE
### Function: NewDmsgData
Returns the DispatchMessage required inputs as a [dMsgData](###dMsgData) struct. This struct consists of
```
* receiver address
* fee : big.NewInt(100 * params.GWei)
* deadline : big.NewInt(10000000000)
* nonce : a sufficiently high and unique value. Check link below for nonce issue
* data : []byte{0}
```
```
func NewDmsgData(ks *keystore.KeyStore, nonceAddr common.Address, v int64, ac accs, ec ethclient.Client, c ctx, r *rand.Rand, chainid *big.Int) (dMsgData, int, int) {
//Randomly select sender and receiver (for deposit and withdraw sender
//and receiver is the same account)from accounts loaded from local keystore.
si := r.Intn(len(ac)) // sender's index (from accs slice)
sender := ac[si]
ri := r.Intn(len(ac)) // receiver's index (from accs slice)
receiver := ac[si]
//Calculate sender balance
bal := CalculateFunds(ec, c, sender)
//Create bind.TransactOpts which essentially is a struct representing
//the transaction signer (from the account decrypted key)
txOpts, _ := bind.NewKeyStoreTransactorWithChainID(ks, sender, chainid)
//Calculate the sender's transaction count from network
_sendernonce, _ := ec.NonceAt(c, sender.Address, nil)
senderNonce := big.NewInt(int64(_sendernonce))
//nonceAddress is a utility variable to experiment with different values
//for the function.nonce. client uses this parameter to pass in the contract
//address and calculate the contract nonce
nonceAddress := nonceAddr
Nonce_uint64, _ := ec.NonceAt(c, nonceAddress, nil)
Nonce := big.NewInt(int64(Nonce_uint64))
//A fixed large nonce value
dispMsgNonce, _ := hexutil.DecodeBig("0xffffff")
//estimate the needed gas
egl, _ := ec.EstimateGas(c, ethereum.CallMsg{
// To: &contractAddress, >> returns: Served eth_estimateGas err="execution reverted"
To: &sender.Address,
Data: []byte{0},
})
//set the amount (as an element of bind.TransactOpts) to transfer
//as a fracture of the sender's balance
txOpts.Value = new(big.Int).Div(bal, big.NewInt(v))
//set the Tx nonce (as an element of bind.TransactOpts) equal to
//the sender's nonce calculated before
txOpts.Nonce = senderNonce
txOpts.GasLimit = uint64(float64(egl) * 10)
txOpts.GasPrice, _ = ec.SuggestGasPrice(c)
fmt.Printf("DUMMY PRINT TO AVOID VARIABLE NOT USED ERROR: %v %v\n", Nonce, dispMsgNonce)
return dMsgData{
txOpts,
receiver.Address,
big.NewInt(100 * params.GWei),
big.NewInt(10000000000),
//set the dispatchMethod nonce. latest attempt is to
//populate with the contract nonce
// senderNonce,
// dispMsgNonce,
Nonce,
[]byte{
0x0,
},
},
si,
ri
}
```
<font size="4">[NewDmsgData.nonce issue](#Issue-with-dispatchMessage.nonce) </font>
### dMsgData
```
type dMsgData struct {
_txOpts *bind.TransactOpts
_to common.Address
_fee *big.Int
_deadline *big.Int
_nonce *big.Int
_data []byte
}
```
and the TransactionOptions as a new transaction signer in the form of a [TransactOpts](https://pkg.go.dev/github.com/ethereum/go-ethereum/accounts/abi/bind#TransactOpts) struct, consisting of
```
From common.Address // Ethereum account to send the transaction from
Nonce *big.Int // Nonce to use for the transaction execution (nil = use pending state)
Signer SignerFn // Method to use for signing the transaction (mandatory)
Value *big.Int // Funds to transfer along the transaction (nil = 0 = no funds)
GasPrice *big.Int // Gas price to use for the transaction execution (nil = gas price oracle)
GasFeeCap *big.Int // Gas fee cap to use for the 1559 transaction execution (nil = gas price oracle)
GasTipCap *big.Int // Gas priority fee cap to use for the 1559 transaction execution (nil = gas price oracle)
GasLimit uint64 // Gas limit to set for the transaction execution (0 = estimate)
Context context.Context // Network context to support cancellation and timeouts (nil = no timeout)
NoSend bool // Do all transact steps but do not send the transaction
```
The following TransactOpts struct's elements are explicitly defined (the ones not mentioned are the default values as returned by function [NewKeyStoreTransactorWithChainID](https://github.com/ethereum/go-ethereum/blob/v1.10.17/accounts/abi/bind/auth.go#L122)):
```
* Value : derived as a fracture (1/1000000) of the sender account balance
* Nonce : account nonce (in L1 for deposits L1>L2, in L2 for withdraws L2>L1), derived from Client.NonceAt
* GasLimit : defined as 10 times Client.EstimateGas
* GasPrice : calculated as Client.SuggestGasPrice
```
<font size="4">[Client.EstimateGas](https://github.com/ethereum/go-ethereum/blob/v1.10.17/ethclient/ethclient.go#L505) </font>
<font size="4">[Client.SuggestGasPrice](https://github.com/ethereum/go-ethereum/blob/v1.10.17/ethclient/ethclient.go#L483) </font>
<font size="4">[Client.NonceAt](https://github.com/ethereum/go-ethereum/blob/v1.10.17/ethclient/ethclient.go#L355) </font>
---
# Fund Deposits L1>L2
```
- Create an rpc client and connect to the l1 rpc endpoint with ethcl.ethclient.Dial(l1-url)
- Retrieve chain ID as ethcl.NetworkID()
- Create a bridge instance as bridge=zkevml1bridge.NewZkevml1bridge(bridgeAddress, ethcl). bridgeAddress is 936a70c0b28532aa22240dce21f89a8399d6ac60 and ethcl is the rpc client from previous step
- Create the dispatchMessage required inputs with custom function NewDmsgData
- Create/Send a Tx invoking the dispatchMessage contract method with bridge.DispatchMessage() that takes in the dMsgData struct's values as inputs
```
<font size="4">[ethclient.Dial](https://pkg.go.dev/github.com/ethereum/go-ethereum/ethclient#Dial) </font>
<font size="4">[ethclient.NetworkID](https://pkg.go.dev/github.com/ethereum/go-ethereum/ethclient#Client.NetworkID) </font>
<font size="4">[NewDmsgData](###Function:-NewDmsgData) </font>
---
# Fund Withdraws L2>L1
```
- Create an rpc client and connect to the l2 rpc endpoint with ethcl.ethclient.Dial(l2-url)
- Retrieve chain ID as ethcl.NetworkID()
- Create a zkevmmessagedispatcher instance as bridge=zkevmmessagedispatcher.NewZkevmmessagedispatcher(bridgeAddress, ethcl). bridgeAddress is 0000000000000000000000000000000000020000 and ethcl is the rpc client from previous step
- Create the dispatchMessage required inputs with custom function NewDmsgData
- Create/Send a Tx invoking the dispatchMessage contract method with bridge.DispatchMessage() that takes in the dMsgData struct's values as inputs
```
---
# Issue with dispatchMessage.nonce
### L1 > L2
```
While fund transfers from L1 to L2 are completed, L1 geth always returns a "nonce too low" error. I have tried to populate the dispatchMessage.nonce value with various approaches, (listed below) but the error is always returned, regardless of the transaction succeeding!
1. use the same nonce value as in the Transaction Options, aka the sender account nonce
2. use the contract nonce, derived as
contractNonce_uint64, _ := ethclient.NonceAt(c, contractAddress, nil)
and then converted to big int. (i think this always returns nil >> is this normal?)
3. use a sufficiently large value, for example "0xffffff"
4. use the miner account nonce
```
### L2 > L1
```
Based on the coordinator logs, transaction looks to be processed.
zkevm-chain-coordinator-1 | [2022-05-17T10:12:36Z INFO coordinator::shared_state] L1:deliverMessageWithProof: skip=false MessageBeacon { id: 0x758dd3f60f3f4425be035a0b9ed7c263475f347ccfe641b1832c2334886df7c7, from: 0x7a862f842f389c163e98b622bad45228d0d8dd48, to: 0x7a862f842f389c163e98b622bad45228d0d8dd48, value: 3743102633306653788481280981, fee: 100000000000, deadline: 10000000000, nonce: 11, calldata: [0] }
Similarly to fund deposits to L1, layer 2 returns an ERROR: already known.
```