mirror of
https://github.com/arnaucube/hermez-node.git
synced 2026-02-07 03:16:45 +01:00
Update coordinator to work better under real net
- cli / node
- Update handler of SIGINT so that after 3 SIGINTs, the process terminates
unconditionally
- coordinator
- Store stats without pointer
- In all functions that send a variable via channel, check for context done
to avoid deadlock (due to no process reading from the channel, which has
no queue) when the node is stopped.
- Abstract `canForge` so that it can be used outside of the `Coordinator`
- In `canForge` check the blockNumber in current and next slot.
- Update tests due to smart contract changes in slot handling, and minimum
bid defaults
- TxManager
- Add consts, vars and stats to allow evaluating `canForge`
- Add `canForge` method (not used yet)
- Store batch and nonces status (last success and last pending)
- Track nonces internally instead of relying on the ethereum node (this
is required to work with ganache when there are pending txs)
- Handle the (common) case of the receipt not being found after the tx
is sent.
- Don't start the main loop until we get an initial messae fo the stats
and vars (so that in the loop the stats and vars are set to
synchronizer values)
- eth / ethereum client
- Add necessary methods to create the auth object for transactions manually
so that we can set the nonce, gas price, gas limit, etc manually
- Update `RollupForgeBatch` to take an auth object as input (so that the
coordinator can set parameters manually)
- synchronizer
- In stats, add `NextSlot`
This commit is contained in:
@@ -6,6 +6,7 @@ import (
|
||||
"math/big"
|
||||
"time"
|
||||
|
||||
"github.com/ethereum/go-ethereum"
|
||||
"github.com/ethereum/go-ethereum/accounts"
|
||||
"github.com/ethereum/go-ethereum/accounts/abi/bind"
|
||||
ethKeystore "github.com/ethereum/go-ethereum/accounts/keystore"
|
||||
@@ -35,6 +36,12 @@ type EthereumInterface interface {
|
||||
|
||||
EthERC20Consts(ethCommon.Address) (*ERC20Consts, error)
|
||||
EthChainID() (*big.Int, error)
|
||||
|
||||
EthPendingNonceAt(ctx context.Context, account ethCommon.Address) (uint64, error)
|
||||
EthNonceAt(ctx context.Context, account ethCommon.Address, blockNumber *big.Int) (uint64, error)
|
||||
EthSuggestGasPrice(ctx context.Context) (*big.Int, error)
|
||||
EthKeyStore() *ethKeystore.KeyStore
|
||||
EthCall(ctx context.Context, tx *types.Transaction, blockNum *big.Int) ([]byte, error)
|
||||
}
|
||||
|
||||
var (
|
||||
@@ -118,6 +125,43 @@ func (c *EthereumClient) EthAddress() (*ethCommon.Address, error) {
|
||||
return &c.account.Address, nil
|
||||
}
|
||||
|
||||
// EthSuggestGasPrice retrieves the currently suggested gas price to allow a
|
||||
// timely execution of a transaction.
|
||||
func (c *EthereumClient) EthSuggestGasPrice(ctx context.Context) (*big.Int, error) {
|
||||
return c.client.SuggestGasPrice(ctx)
|
||||
}
|
||||
|
||||
// EthKeyStore returns the keystore in the EthereumClient
|
||||
func (c *EthereumClient) EthKeyStore() *ethKeystore.KeyStore {
|
||||
return c.ks
|
||||
}
|
||||
|
||||
// NewAuth builds a new auth object to make a transaction
|
||||
func (c *EthereumClient) NewAuth() (*bind.TransactOpts, error) {
|
||||
if c.account == nil {
|
||||
return nil, tracerr.Wrap(ErrAccountNil)
|
||||
}
|
||||
|
||||
gasPrice, err := c.client.SuggestGasPrice(context.Background())
|
||||
if err != nil {
|
||||
return nil, tracerr.Wrap(err)
|
||||
}
|
||||
inc := new(big.Int).Set(gasPrice)
|
||||
inc.Div(inc, new(big.Int).SetUint64(c.config.GasPriceDiv))
|
||||
gasPrice.Add(gasPrice, inc)
|
||||
log.Debugw("Transaction metadata", "gasPrice", gasPrice)
|
||||
|
||||
auth, err := bind.NewKeyStoreTransactorWithChainID(c.ks, *c.account, c.chainID)
|
||||
if err != nil {
|
||||
return nil, tracerr.Wrap(err)
|
||||
}
|
||||
auth.Value = big.NewInt(0) // in wei
|
||||
auth.GasLimit = c.config.CallGasLimit
|
||||
auth.GasPrice = gasPrice
|
||||
|
||||
return auth, nil
|
||||
}
|
||||
|
||||
// CallAuth performs a Smart Contract method call that requires authorization.
|
||||
// This call requires a valid account with Ether that can be spend during the
|
||||
// call.
|
||||
@@ -250,3 +294,35 @@ func newCallOpts() *bind.CallOpts {
|
||||
From: ethCommon.HexToAddress("0x0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f"),
|
||||
}
|
||||
}
|
||||
|
||||
// EthPendingNonceAt returns the account nonce of the given account in the pending
|
||||
// state. This is the nonce that should be used for the next transaction.
|
||||
func (c *EthereumClient) EthPendingNonceAt(ctx context.Context,
|
||||
account ethCommon.Address) (uint64, error) {
|
||||
return c.client.PendingNonceAt(ctx, account)
|
||||
}
|
||||
|
||||
// EthNonceAt returns the account nonce of the given account. The block number can
|
||||
// be nil, in which case the nonce is taken from the latest known block.
|
||||
func (c *EthereumClient) EthNonceAt(ctx context.Context,
|
||||
account ethCommon.Address, blockNumber *big.Int) (uint64, error) {
|
||||
return c.client.NonceAt(ctx, account, blockNumber)
|
||||
}
|
||||
|
||||
// EthCall runs the transaction as a call (without paying) in the local node at
|
||||
// blockNum.
|
||||
func (c *EthereumClient) EthCall(ctx context.Context, tx *types.Transaction,
|
||||
blockNum *big.Int) ([]byte, error) {
|
||||
if c.account == nil {
|
||||
return nil, tracerr.Wrap(ErrAccountNil)
|
||||
}
|
||||
msg := ethereum.CallMsg{
|
||||
From: c.account.Address,
|
||||
To: tx.To(),
|
||||
Gas: tx.Gas(),
|
||||
GasPrice: tx.GasPrice(),
|
||||
Value: tx.Value(),
|
||||
Data: tx.Data(),
|
||||
}
|
||||
return c.client.CallContract(ctx, msg, blockNum)
|
||||
}
|
||||
|
||||
137
eth/rollup.go
137
eth/rollup.go
@@ -242,7 +242,7 @@ type RollupInterface interface {
|
||||
|
||||
// Public Functions
|
||||
|
||||
RollupForgeBatch(*RollupForgeBatchArgs) (*types.Transaction, error)
|
||||
RollupForgeBatch(*RollupForgeBatchArgs, *bind.TransactOpts) (*types.Transaction, error)
|
||||
RollupAddToken(tokenAddress ethCommon.Address, feeAddToken, deadline *big.Int) (*types.Transaction, error)
|
||||
|
||||
RollupWithdrawMerkleProof(babyPubKey babyjub.PublicKeyComp, tokenID uint32, numExitRoot, idx int64, amount *big.Int, siblings []*big.Int, instantWithdraw bool) (*types.Transaction, error)
|
||||
@@ -323,70 +323,77 @@ func NewRollupClient(client *EthereumClient, address ethCommon.Address, tokenHEZ
|
||||
}
|
||||
|
||||
// RollupForgeBatch is the interface to call the smart contract function
|
||||
func (c *RollupClient) RollupForgeBatch(args *RollupForgeBatchArgs) (tx *types.Transaction, err error) {
|
||||
if tx, err = c.client.CallAuth(
|
||||
1000000, //nolint:gomnd
|
||||
func(ec *ethclient.Client, auth *bind.TransactOpts) (*types.Transaction, error) {
|
||||
nLevels := c.consts.Verifiers[args.VerifierIdx].NLevels
|
||||
lenBytes := nLevels / 8 //nolint:gomnd
|
||||
newLastIdx := big.NewInt(int64(args.NewLastIdx))
|
||||
// L1CoordinatorBytes
|
||||
var l1CoordinatorBytes []byte
|
||||
for i := 0; i < len(args.L1CoordinatorTxs); i++ {
|
||||
l1 := args.L1CoordinatorTxs[i]
|
||||
bytesl1, err := l1.BytesCoordinatorTx(args.L1CoordinatorTxsAuths[i])
|
||||
if err != nil {
|
||||
return nil, tracerr.Wrap(err)
|
||||
}
|
||||
l1CoordinatorBytes = append(l1CoordinatorBytes, bytesl1[:]...)
|
||||
}
|
||||
// L1L2TxData
|
||||
var l1l2TxData []byte
|
||||
for i := 0; i < len(args.L1UserTxs); i++ {
|
||||
l1User := args.L1UserTxs[i]
|
||||
bytesl1User, err := l1User.BytesDataAvailability(uint32(nLevels))
|
||||
if err != nil {
|
||||
return nil, tracerr.Wrap(err)
|
||||
}
|
||||
l1l2TxData = append(l1l2TxData, bytesl1User[:]...)
|
||||
}
|
||||
for i := 0; i < len(args.L1CoordinatorTxs); i++ {
|
||||
l1Coord := args.L1CoordinatorTxs[i]
|
||||
bytesl1Coord, err := l1Coord.BytesDataAvailability(uint32(nLevels))
|
||||
if err != nil {
|
||||
return nil, tracerr.Wrap(err)
|
||||
}
|
||||
l1l2TxData = append(l1l2TxData, bytesl1Coord[:]...)
|
||||
}
|
||||
for i := 0; i < len(args.L2TxsData); i++ {
|
||||
l2 := args.L2TxsData[i]
|
||||
bytesl2, err := l2.BytesDataAvailability(uint32(nLevels))
|
||||
if err != nil {
|
||||
return nil, tracerr.Wrap(err)
|
||||
}
|
||||
l1l2TxData = append(l1l2TxData, bytesl2[:]...)
|
||||
}
|
||||
// FeeIdxCoordinator
|
||||
var feeIdxCoordinator []byte
|
||||
if len(args.FeeIdxCoordinator) > common.RollupConstMaxFeeIdxCoordinator {
|
||||
return nil, tracerr.Wrap(fmt.Errorf("len(args.FeeIdxCoordinator) > %v",
|
||||
common.RollupConstMaxFeeIdxCoordinator))
|
||||
}
|
||||
for i := 0; i < common.RollupConstMaxFeeIdxCoordinator; i++ {
|
||||
feeIdx := common.Idx(0)
|
||||
if i < len(args.FeeIdxCoordinator) {
|
||||
feeIdx = args.FeeIdxCoordinator[i]
|
||||
}
|
||||
bytesFeeIdx, err := feeIdx.Bytes()
|
||||
if err != nil {
|
||||
return nil, tracerr.Wrap(err)
|
||||
}
|
||||
feeIdxCoordinator = append(feeIdxCoordinator, bytesFeeIdx[len(bytesFeeIdx)-int(lenBytes):]...)
|
||||
}
|
||||
return c.hermez.ForgeBatch(auth, newLastIdx, args.NewStRoot, args.NewExitRoot, l1CoordinatorBytes, l1l2TxData, feeIdxCoordinator, args.VerifierIdx, args.L1Batch, args.ProofA, args.ProofB, args.ProofC)
|
||||
},
|
||||
); err != nil {
|
||||
return nil, tracerr.Wrap(fmt.Errorf("Failed forge batch: %w", err))
|
||||
func (c *RollupClient) RollupForgeBatch(args *RollupForgeBatchArgs, auth *bind.TransactOpts) (tx *types.Transaction, err error) {
|
||||
if auth == nil {
|
||||
auth, err := c.client.NewAuth()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
auth.GasLimit = 1000000
|
||||
}
|
||||
|
||||
nLevels := c.consts.Verifiers[args.VerifierIdx].NLevels
|
||||
lenBytes := nLevels / 8 //nolint:gomnd
|
||||
newLastIdx := big.NewInt(int64(args.NewLastIdx))
|
||||
// L1CoordinatorBytes
|
||||
var l1CoordinatorBytes []byte
|
||||
for i := 0; i < len(args.L1CoordinatorTxs); i++ {
|
||||
l1 := args.L1CoordinatorTxs[i]
|
||||
bytesl1, err := l1.BytesCoordinatorTx(args.L1CoordinatorTxsAuths[i])
|
||||
if err != nil {
|
||||
return nil, tracerr.Wrap(err)
|
||||
}
|
||||
l1CoordinatorBytes = append(l1CoordinatorBytes, bytesl1[:]...)
|
||||
}
|
||||
// L1L2TxData
|
||||
var l1l2TxData []byte
|
||||
for i := 0; i < len(args.L1UserTxs); i++ {
|
||||
l1User := args.L1UserTxs[i]
|
||||
bytesl1User, err := l1User.BytesDataAvailability(uint32(nLevels))
|
||||
if err != nil {
|
||||
return nil, tracerr.Wrap(err)
|
||||
}
|
||||
l1l2TxData = append(l1l2TxData, bytesl1User[:]...)
|
||||
}
|
||||
for i := 0; i < len(args.L1CoordinatorTxs); i++ {
|
||||
l1Coord := args.L1CoordinatorTxs[i]
|
||||
bytesl1Coord, err := l1Coord.BytesDataAvailability(uint32(nLevels))
|
||||
if err != nil {
|
||||
return nil, tracerr.Wrap(err)
|
||||
}
|
||||
l1l2TxData = append(l1l2TxData, bytesl1Coord[:]...)
|
||||
}
|
||||
for i := 0; i < len(args.L2TxsData); i++ {
|
||||
l2 := args.L2TxsData[i]
|
||||
bytesl2, err := l2.BytesDataAvailability(uint32(nLevels))
|
||||
if err != nil {
|
||||
return nil, tracerr.Wrap(err)
|
||||
}
|
||||
l1l2TxData = append(l1l2TxData, bytesl2[:]...)
|
||||
}
|
||||
// FeeIdxCoordinator
|
||||
var feeIdxCoordinator []byte
|
||||
if len(args.FeeIdxCoordinator) > common.RollupConstMaxFeeIdxCoordinator {
|
||||
return nil, tracerr.Wrap(fmt.Errorf("len(args.FeeIdxCoordinator) > %v",
|
||||
common.RollupConstMaxFeeIdxCoordinator))
|
||||
}
|
||||
for i := 0; i < common.RollupConstMaxFeeIdxCoordinator; i++ {
|
||||
feeIdx := common.Idx(0)
|
||||
if i < len(args.FeeIdxCoordinator) {
|
||||
feeIdx = args.FeeIdxCoordinator[i]
|
||||
}
|
||||
bytesFeeIdx, err := feeIdx.Bytes()
|
||||
if err != nil {
|
||||
return nil, tracerr.Wrap(err)
|
||||
}
|
||||
feeIdxCoordinator = append(feeIdxCoordinator,
|
||||
bytesFeeIdx[len(bytesFeeIdx)-int(lenBytes):]...)
|
||||
}
|
||||
tx, err = c.hermez.ForgeBatch(auth, newLastIdx, args.NewStRoot, args.NewExitRoot,
|
||||
l1CoordinatorBytes, l1l2TxData, feeIdxCoordinator, args.VerifierIdx, args.L1Batch,
|
||||
args.ProofA, args.ProofB, args.ProofC)
|
||||
if err != nil {
|
||||
return nil, tracerr.Wrap(fmt.Errorf("Failed Hermez.ForgeBatch: %w", err))
|
||||
}
|
||||
return tx, nil
|
||||
}
|
||||
|
||||
@@ -169,7 +169,9 @@ func TestRollupForgeBatch(t *testing.T) {
|
||||
args.ProofC[1] = big.NewInt(0)
|
||||
|
||||
argsForge = args
|
||||
_, err = rollupClient.RollupForgeBatch(argsForge)
|
||||
auth, err := rollupClient.client.NewAuth()
|
||||
require.NoError(t, err)
|
||||
_, err = rollupClient.RollupForgeBatch(argsForge, auth)
|
||||
require.NoError(t, err)
|
||||
|
||||
currentBlockNum, err = rollupClient.client.EthLastBlock()
|
||||
@@ -818,7 +820,9 @@ func TestRollupL1UserTxERC20PermitForceExit(t *testing.T) {
|
||||
|
||||
func TestRollupForgeBatch2(t *testing.T) {
|
||||
// Forge Batch 2
|
||||
_, err := rollupClient.RollupForgeBatch(argsForge)
|
||||
auth, err := rollupClient.client.NewAuth()
|
||||
require.NoError(t, err)
|
||||
_, err = rollupClient.RollupForgeBatch(argsForge, auth)
|
||||
require.NoError(t, err)
|
||||
currentBlockNum, err := rollupClient.client.EthLastBlock()
|
||||
require.NoError(t, err)
|
||||
@@ -871,7 +875,9 @@ func TestRollupForgeBatch2(t *testing.T) {
|
||||
|
||||
argsForge = args
|
||||
|
||||
_, err = rollupClient.RollupForgeBatch(argsForge)
|
||||
auth, err = rollupClient.client.NewAuth()
|
||||
require.NoError(t, err)
|
||||
_, err = rollupClient.RollupForgeBatch(argsForge, auth)
|
||||
require.NoError(t, err)
|
||||
|
||||
currentBlockNum, err = rollupClient.client.EthLastBlock()
|
||||
|
||||
Reference in New Issue
Block a user