From 003c353f05e2709422d3ff809bef662ffad52619 Mon Sep 17 00:00:00 2001 From: Eduard S Date: Thu, 3 Sep 2020 13:04:36 +0200 Subject: [PATCH] Add ethclient full skeleton --- common/zk.go | 5 - coordinator/coordinator.go | 6 +- coordinator/coordinator_test.go | 3 +- eth/auction.go | 380 ++++++++++++++++++++++++++++++++ eth/client.go | 249 ++------------------- eth/ethereum.go | 244 ++++++++++++++++++++ eth/interface.go | 18 -- eth/rollup.go | 298 +++++++++++++++++++++++++ synchronizer/synchronizer.go | 14 +- test/ethclient.go | 288 ++++++++++++++++++++++-- test/ethclient_test.go | 8 +- 11 files changed, 1237 insertions(+), 276 deletions(-) create mode 100644 eth/auction.go create mode 100644 eth/ethereum.go delete mode 100644 eth/interface.go create mode 100644 eth/rollup.go diff --git a/common/zk.go b/common/zk.go index 8460b56..d7d6892 100644 --- a/common/zk.go +++ b/common/zk.go @@ -144,8 +144,3 @@ type ZKInputs struct { ethAddr3 []*big.Int // ethCommon.Address, len: [maxFeeTx] siblings3 [][]*big.Int // Hash, len: [maxFeeTx][nLevels + 1] } - -// CallDataForge TBD -type CallDataForge struct { - // TBD -} diff --git a/coordinator/coordinator.go b/coordinator/coordinator.go index 84ecf3b..a2d1d1b 100644 --- a/coordinator/coordinator.go +++ b/coordinator/coordinator.go @@ -255,8 +255,8 @@ func (c *Coordinator) proveSequence() error { return err } batchInfo.SetProof(proof) - callData := c.prepareCallDataForge(batchInfo) - _, err = c.ethClient.ForgeCall(callData) + forgeBatchArgs := c.prepareForgeBatchArgs(batchInfo) + _, err = c.ethClient.RollupForgeBatch(forgeBatchArgs) if err != nil { return err } @@ -306,6 +306,6 @@ func (c *Coordinator) shouldL1L2Batch() bool { return false } -func (c *Coordinator) prepareCallDataForge(batchInfo *BatchInfo) *common.CallDataForge { +func (c *Coordinator) prepareForgeBatchArgs(batchInfo *BatchInfo) *eth.RollupForgeBatchArgs { return nil } diff --git a/coordinator/coordinator_test.go b/coordinator/coordinator_test.go index e2b2172..8aaaaca 100644 --- a/coordinator/coordinator_test.go +++ b/coordinator/coordinator_test.go @@ -10,6 +10,7 @@ import ( "github.com/hermeznetwork/hermez-node/db/historydb" "github.com/hermeznetwork/hermez-node/db/l2db" "github.com/hermeznetwork/hermez-node/db/statedb" + "github.com/hermeznetwork/hermez-node/eth" "github.com/hermeznetwork/hermez-node/log" "github.com/hermeznetwork/hermez-node/txselector" "github.com/stretchr/testify/assert" @@ -50,7 +51,7 @@ func TestCoordinator(t *testing.T) { LoopInterval: 100 * time.Millisecond, } hdb := &historydb.HistoryDB{} - c := NewCoordinator(conf, hdb, txsel, bb, nil) + c := NewCoordinator(conf, hdb, txsel, bb, ð.Client{}) c.Start() time.Sleep(1 * time.Second) diff --git a/eth/auction.go b/eth/auction.go new file mode 100644 index 0000000..0c27854 --- /dev/null +++ b/eth/auction.go @@ -0,0 +1,380 @@ +package eth + +import ( + "math/big" + + ethCommon "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/core/types" +) + +// AuctionConstants are the constants of the Rollup Smart Contract +type AuctionConstants struct { + // Blocks to wait before starting with the first slot + DelayGenesis uint16 + // Blocks per slot + BlocksPerSlot uint8 + // Minimum bid when no one has bid yet + InitialMinimalBidding *big.Int + // First block where the first slot begins + GenesisBlockNum int64 + // Hermez Governanze Token smartcontract address who controls some parameters and collects HEZ fee + GovernanceAddress ethCommon.Address + // ERC777 token with which the bids will be made + TokenHEZ ethCommon.Address + // HermezRollup smartcontract address + HermezRollup ethCommon.Address +} + +// SlotState is the state of a slot +type SlotState struct { + Forger ethCommon.Address + BidAmount *big.Int + ClosedMinBid *big.Int + Fulfilled bool +} + +// Coordinator is the details of the Coordinator identified by the forger address +type Coordinator struct { + WithdrawalAddress ethCommon.Address + URL string +} + +// AuctionVariables are the variables of the Auction Smart Contract +type AuctionVariables struct { + // Boot Coordinator Address + DonationAddress ethCommon.Address + // Boot Coordinator Address + BootCoordinator ethCommon.Address + // The minimum bid value in a series of 6 slots + MinBidEpoch [6]*big.Int + // Distance (#slots) to the closest slot to which you can bid ( 2 Slots = 2 * 40 Blocks = 20 min ) + ClosedAuctionSlots uint16 + // Distance (#slots) to the farthest slot to which you can bid (30 days = 4320 slots ) + OpenAuctionSlots uint16 + // How the HEZ tokens deposited by the slot winner are distributed (Burn: 40% - Donation: 40% - HGT: 20%) + AllocationRatio [3]uint8 + // Minimum outbid (percentage) over the previous one to consider it valid + Outbidding uint8 + // Number of blocks at the end of a slot in which any coordinator can forge if the winner has not forged one before + SlotDeadline uint8 +} + +// AuctionState represents the state of the Rollup in the Smart Contract +type AuctionState struct { + // Mapping to control slot state + Slots map[int64]SlotState + // Mapping to control balances pending to claim + PendingBalances map[ethCommon.Address]*big.Int + + // Mapping to register all the coordinators. The address used for the mapping is the forger address + Coordinators map[ethCommon.Address]Coordinator +} + +// AuctionEventNewBid is an event of the Auction Smart Contract +type AuctionEventNewBid struct { + Slot int64 + BidAmount *big.Int + CoordinatorForger ethCommon.Address +} + +// AuctionEventNewSlotDeadline is an event of the Auction Smart Contract +type AuctionEventNewSlotDeadline struct { + NewSlotDeadline uint8 +} + +// AuctionEventNewClosedAuctionSlots is an event of the Auction Smart Contract +type AuctionEventNewClosedAuctionSlots struct { + NewClosedAuctionSlots uint16 +} + +// AuctionEventNewOutbidding is an event of the Auction Smart Contract +type AuctionEventNewOutbidding struct { + NewOutbidding uint8 +} + +// AuctionEventNewDonationAddress is an event of the Auction Smart Contract +type AuctionEventNewDonationAddress struct { + NewDonationAddress ethCommon.Address +} + +// AuctionEventNewBootCoordinator is an event of the Auction Smart Contract +type AuctionEventNewBootCoordinator struct { + NewBootCoordinator ethCommon.Address +} + +// AuctionEventNewOpenAuctionSlots is an event of the Auction Smart Contract +type AuctionEventNewOpenAuctionSlots struct { + NewOpenAuctionSlots uint16 +} + +// AuctionEventNewAllocationRatio is an event of the Auction Smart Contract +type AuctionEventNewAllocationRatio struct { + NewAllocationRatio [3]uint8 +} + +// AuctionEventNewCoordinator is an event of the Auction Smart Contract +type AuctionEventNewCoordinator struct { + ForgerAddress ethCommon.Address + WithdrawalAddress ethCommon.Address + URL string +} + +// AuctionEventCoordinatorUpdated is an event of the Auction Smart Contract +type AuctionEventCoordinatorUpdated struct { + ForgerAddress ethCommon.Address + WithdrawalAddress ethCommon.Address + URL string +} + +// AuctionEventNewForgeAllocated is an event of the Auction Smart Contract +type AuctionEventNewForgeAllocated struct { + Forger ethCommon.Address + CurrentSlot int64 + BurnAmount *big.Int + DonationAmount *big.Int + GovernanceAmount *big.Int +} + +// AuctionEventNewMinBidEpoch is an event of the Auction Smart Contract +type AuctionEventNewMinBidEpoch struct { + SlotEpoch int64 + NewInitialMinBid *big.Int +} + +// AuctionEventNewForge is an event of the Auction Smart Contract +type AuctionEventNewForge struct { + Forger ethCommon.Address + CurrentSlot int64 +} + +// AuctionEventHEZClaimed is an event of the Auction Smart Contract +type AuctionEventHEZClaimed struct { + Owner ethCommon.Address + Amount *big.Int +} + +// AuctionEvents is the list of events in a block of the Auction Smart Contract +type AuctionEvents struct { //nolint:structcheck + NewBid []AuctionEventNewBid + NewSlotDeadline []AuctionEventNewSlotDeadline + NewClosedAuctionSlots []AuctionEventNewClosedAuctionSlots + NewOutbidding []AuctionEventNewOutbidding + NewDonationAddress []AuctionEventNewDonationAddress + NewBootCoordinator []AuctionEventNewBootCoordinator + NewOpenAuctionSlots []AuctionEventNewOpenAuctionSlots + NewAllocationRatio []AuctionEventNewAllocationRatio + NewCoordinator []AuctionEventNewCoordinator + CoordinatorUpdated []AuctionEventCoordinatorUpdated + NewForgeAllocated []AuctionEventNewForgeAllocated + NewMinBidEpoch []AuctionEventNewMinBidEpoch + NewForge []AuctionEventNewForge + HEZClaimed []AuctionEventHEZClaimed +} + +// AuctionInterface is the inteface to to Auction Smart Contract +type AuctionInterface interface { + // + // Smart Contract Methods + // + + // Getter/Setter, where Setter is onlyOwner + AuctionSetSlotDeadline(newDeadline uint8) (*types.Transaction, error) + AuctionGetSlotDeadline() (uint8, error) + AuctionSetOpenAuctionSlots(newOpenAuctionSlots uint16) (*types.Transaction, error) + AuctionGetOpenAuctionSlots() (uint16, error) + AuctionSetClosedAuctionSlots(newClosedAuctionSlots uint16) (*types.Transaction, error) + AuctionGetClosedAuctionSlots() (uint16, error) + AuctionSetOutbidding(newOutbidding uint8) (*types.Transaction, error) + AuctionGetOutbidding() (uint8, error) + AuctionSetAllocationRatio(newAllocationRatio [3]uint8) (*types.Transaction, error) + AuctionGetAllocationRatio() ([3]uint8, error) + AuctionSetDonationAddress(newDonationAddress ethCommon.Address) (*types.Transaction, error) + AuctionGetDonationAddress() (*ethCommon.Address, error) + AuctionSetBootCoordinator(newBootCoordinator ethCommon.Address) (*types.Transaction, error) + AuctionGetBootCoordinator() (*ethCommon.Address, error) + AuctionChangeEpochMinBid(slotEpoch int64, newInitialMinBid *big.Int) (*types.Transaction, error) + + // Coordinator Management + AuctionRegisterCoordinator(forgerAddress ethCommon.Address, URL string) (*types.Transaction, error) + AuctionIsRegisteredCoordinator(forgerAddress ethCommon.Address) (bool, error) + AuctionUpdateCoordinatorInfo(forgerAddress ethCommon.Address, newWithdrawAddress ethCommon.Address, newURL string) (*types.Transaction, error) + + // Slot Info + AuctionGetCurrentSlotNumber() (int64, error) + AuctionGetMinBidBySlot(slot int64) (*big.Int, error) + AuctionGetMinBidEpoch(epoch uint8) (*big.Int, error) + + // Bidding + // AuctionTokensReceived(operator, from, to ethCommon.Address, amount *big.Int, + // userData, operatorData []byte) error // Only called from another smart contract + AuctionBid(slot int64, bidAmount *big.Int, forger ethCommon.Address) (*types.Transaction, error) + AuctionMultiBid(startingSlot int64, endingSlot int64, slotEpoch [6]bool, + maxBid, closedMinBid, budget *big.Int, forger ethCommon.Address) (*types.Transaction, error) + + // Forge + AuctionCanForge(forger ethCommon.Address) (bool, error) + // AuctionForge(forger ethCommon.Address) (bool, error) // Only called from another smart contract + + // Fees + AuctionClaimHEZ() (*types.Transaction, error) + + // + // Smart Contract Status + // + + AuctionConstants() (*AuctionConstants, error) + AuctionEventsByBlock(blockNum int64) (*AuctionEvents, *ethCommon.Hash, error) +} + +// +// Implementation +// + +// AuctionClient is the implementation of the interface to the Auction Smart Contract in ethereum. +type AuctionClient struct { +} + +// AuctionSetSlotDeadline is the interface to call the smart contract function +func (c *AuctionClient) AuctionSetSlotDeadline(newDeadline uint8) (*types.Transaction, error) { + return nil, errTODO +} + +// AuctionGetSlotDeadline is the interface to call the smart contract function +func (c *AuctionClient) AuctionGetSlotDeadline() (uint8, error) { + return 0, errTODO +} + +// AuctionSetOpenAuctionSlots is the interface to call the smart contract function +func (c *AuctionClient) AuctionSetOpenAuctionSlots(newOpenAuctionSlots uint16) (*types.Transaction, error) { + return nil, errTODO +} + +// AuctionGetOpenAuctionSlots is the interface to call the smart contract function +func (c *AuctionClient) AuctionGetOpenAuctionSlots() (uint16, error) { + return 0, errTODO +} + +// AuctionSetClosedAuctionSlots is the interface to call the smart contract function +func (c *AuctionClient) AuctionSetClosedAuctionSlots(newClosedAuctionSlots uint16) (*types.Transaction, error) { + return nil, errTODO +} + +// AuctionGetClosedAuctionSlots is the interface to call the smart contract function +func (c *AuctionClient) AuctionGetClosedAuctionSlots() (uint16, error) { + return 0, errTODO +} + +// AuctionSetOutbidding is the interface to call the smart contract function +func (c *AuctionClient) AuctionSetOutbidding(newOutbidding uint8) (*types.Transaction, error) { + return nil, errTODO +} + +// AuctionGetOutbidding is the interface to call the smart contract function +func (c *AuctionClient) AuctionGetOutbidding() (uint8, error) { + return 0, errTODO +} + +// AuctionSetAllocationRatio is the interface to call the smart contract function +func (c *AuctionClient) AuctionSetAllocationRatio(newAllocationRatio [3]uint8) (*types.Transaction, error) { + return nil, errTODO +} + +// AuctionGetAllocationRatio is the interface to call the smart contract function +func (c *AuctionClient) AuctionGetAllocationRatio() ([3]uint8, error) { + return [3]uint8{}, errTODO +} + +// AuctionSetDonationAddress is the interface to call the smart contract function +func (c *AuctionClient) AuctionSetDonationAddress(newDonationAddress ethCommon.Address) (*types.Transaction, error) { + return nil, errTODO +} + +// AuctionGetDonationAddress is the interface to call the smart contract function +func (c *AuctionClient) AuctionGetDonationAddress() (*ethCommon.Address, error) { + return nil, errTODO +} + +// AuctionSetBootCoordinator is the interface to call the smart contract function +func (c *AuctionClient) AuctionSetBootCoordinator(newBootCoordinator ethCommon.Address) (*types.Transaction, error) { + return nil, errTODO +} + +// AuctionGetBootCoordinator is the interface to call the smart contract function +func (c *AuctionClient) AuctionGetBootCoordinator() (*ethCommon.Address, error) { + return nil, errTODO +} + +// AuctionChangeEpochMinBid is the interface to call the smart contract function +func (c *AuctionClient) AuctionChangeEpochMinBid(slotEpoch int64, newInitialMinBid *big.Int) (*types.Transaction, error) { + return nil, errTODO +} + +// AuctionRegisterCoordinator is the interface to call the smart contract function +func (c *AuctionClient) AuctionRegisterCoordinator(forgerAddress ethCommon.Address, URL string) (*types.Transaction, error) { + return nil, errTODO +} + +// AuctionIsRegisteredCoordinator is the interface to call the smart contract function +func (c *AuctionClient) AuctionIsRegisteredCoordinator(forgerAddress ethCommon.Address) (bool, error) { + return false, errTODO +} + +// AuctionUpdateCoordinatorInfo is the interface to call the smart contract function +func (c *AuctionClient) AuctionUpdateCoordinatorInfo(forgerAddress ethCommon.Address, newWithdrawAddress ethCommon.Address, newURL string) (*types.Transaction, error) { + return nil, errTODO +} + +// AuctionGetCurrentSlotNumber is the interface to call the smart contract function +func (c *AuctionClient) AuctionGetCurrentSlotNumber() (int64, error) { + return 0, errTODO +} + +// AuctionGetMinBidBySlot is the interface to call the smart contract function +func (c *AuctionClient) AuctionGetMinBidBySlot(slot int64) (*big.Int, error) { + return nil, errTODO +} + +// AuctionGetMinBidEpoch is the interface to call the smart contract function +func (c *AuctionClient) AuctionGetMinBidEpoch(epoch uint8) (*big.Int, error) { + return nil, errTODO +} + +// AuctionTokensReceived is the interface to call the smart contract function +// func (c *AuctionClient) AuctionTokensReceived(operator, from, to ethCommon.Address, amount *big.Int, userData, operatorData []byte) error { +// return errTODO +// } + +// AuctionBid is the interface to call the smart contract function +func (c *AuctionClient) AuctionBid(slot int64, bidAmount *big.Int, forger ethCommon.Address) (*types.Transaction, error) { + return nil, errTODO +} + +// AuctionMultiBid is the interface to call the smart contract function +func (c *AuctionClient) AuctionMultiBid(startingSlot int64, endingSlot int64, slotEpoch [6]bool, maxBid, closedMinBid, budget *big.Int, forger ethCommon.Address) (*types.Transaction, error) { + return nil, errTODO +} + +// AuctionCanForge is the interface to call the smart contract function +func (c *AuctionClient) AuctionCanForge(forger ethCommon.Address) (bool, error) { + return false, errTODO +} + +// AuctionForge is the interface to call the smart contract function +// func (c *AuctionClient) AuctionForge(forger ethCommon.Address) (bool, error) { +// return false, errTODO +// } + +// AuctionClaimHEZ is the interface to call the smart contract function +func (c *AuctionClient) AuctionClaimHEZ() (*types.Transaction, error) { + return nil, errTODO +} + +// AuctionConstants returns the Constants of the Auction Smart Contract +func (c *AuctionClient) AuctionConstants() (*AuctionConstants, error) { + return nil, errTODO +} + +// AuctionEventsByBlock returns the events in a block that happened in the Auction Smart Contract +func (c *AuctionClient) AuctionEventsByBlock(blockNum int64) (*AuctionEvents, *ethCommon.Hash, error) { + return nil, nil, errTODO +} diff --git a/eth/client.go b/eth/client.go index 93e8cc2..0470616 100644 --- a/eth/client.go +++ b/eth/client.go @@ -1,243 +1,42 @@ package eth import ( - "context" "fmt" - "math/big" - "time" "github.com/ethereum/go-ethereum/accounts" - "github.com/ethereum/go-ethereum/accounts/abi/bind" ethKeystore "github.com/ethereum/go-ethereum/accounts/keystore" - ethCommon "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/ethclient" - "github.com/hermeznetwork/hermez-node/common" - "github.com/hermeznetwork/hermez-node/log" ) -var ( - // ErrAccountNil is used when the calls can not be made because the account is nil - ErrAccountNil = fmt.Errorf("Authorized calls can't be made when the account is nil") - // ErrReceiptStatusFailed is used when receiving a failed transaction - ErrReceiptStatusFailed = fmt.Errorf("receipt status is failed") - // ErrReceiptNotReceived is used when unable to retrieve a transaction - ErrReceiptNotReceived = fmt.Errorf("receipt not available") -) - -const ( - errStrDeploy = "deployment of %s failed: %w" - errStrWaitReceipt = "wait receipt of %s deploy failed: %w" - - // default values - defaultCallGasLimit = 300000 - defaultDeployGasLimit = 1000000 - defaultGasPriceDiv = 100 - defaultReceiptTimeout = 60 - defaultIntervalReceiptLoop = 200 -) - -// Config defines the configuration parameters of the Client -type Config struct { - CallGasLimit uint64 - DeployGasLimit uint64 - GasPriceDiv uint64 - ReceiptTimeout time.Duration // in seconds - IntervalReceiptLoop time.Duration // in milliseconds -} - -// Client is an ethereum client to call Smart Contract methods. -type Client struct { - client *ethclient.Client - account *accounts.Account - ks *ethKeystore.KeyStore - ReceiptTimeout time.Duration - config *Config -} - -// NewClient creates a Client instance. The account is not mandatory (it can -// be nil). If the account is nil, CallAuth will fail with ErrAccountNil. -func NewClient(client *ethclient.Client, account *accounts.Account, ks *ethKeystore.KeyStore, config *Config) *Client { - if config == nil { - config = &Config{ - CallGasLimit: defaultCallGasLimit, - DeployGasLimit: defaultDeployGasLimit, - GasPriceDiv: defaultGasPriceDiv, - ReceiptTimeout: defaultReceiptTimeout, - IntervalReceiptLoop: defaultIntervalReceiptLoop, - } - } - return &Client{client: client, account: account, ks: ks, ReceiptTimeout: config.ReceiptTimeout * time.Second, config: config} -} - -// BalanceAt retieves information about the default account -func (c *Client) BalanceAt(addr ethCommon.Address) (*big.Int, error) { - return c.client.BalanceAt(context.TODO(), addr, nil) -} - -// Account returns the underlying ethereum account -func (c *Client) Account() *accounts.Account { - return c.account -} - -// 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. -func (c *Client) CallAuth(gasLimit uint64, - fn func(*ethclient.Client, *bind.TransactOpts) (*types.Transaction, error)) (*types.Transaction, error) { - if c.account == nil { - return nil, ErrAccountNil - } - - gasPrice, err := c.client.SuggestGasPrice(context.Background()) - if err != nil { - return nil, err - } - inc := new(big.Int).Set(gasPrice) - inc.Div(inc, new(big.Int).SetUint64(c.config.GasPriceDiv)) - gasPrice.Add(gasPrice, inc) - log.Debug("Transaction metadata", "gasPrice", gasPrice) - - auth, err := bind.NewKeyStoreTransactor(c.ks, *c.account) - if err != nil { - return nil, err - } - auth.Value = big.NewInt(0) // in wei - if gasLimit == 0 { - auth.GasLimit = c.config.CallGasLimit // in units - } else { - auth.GasLimit = gasLimit // in units - } - auth.GasPrice = gasPrice - - tx, err := fn(c.client, auth) - if tx != nil { - log.Debug("Transaction", "tx", tx.Hash().Hex(), "nonce", tx.Nonce()) - } - return tx, err -} +var errTODO = fmt.Errorf("TODO: Not implemented yet") -// ContractData contains the contract data -type ContractData struct { - Address ethCommon.Address - Tx *types.Transaction - Receipt *types.Receipt +// ClientInterface is the eth Client interface used by hermez-node modules to +// interact with Ethereum Blockchain and smart contracts. +type ClientInterface interface { + EthereumInterface + RollupInterface + AuctionInterface } -// Deploy a smart contract. `name` is used to log deployment information. fn -// is a wrapper to the deploy function generated by abigen. In case of error, -// the returned `ContractData` may have some parameters filled depending on the -// kind of error that occurred. -func (c *Client) Deploy(name string, - fn func(c *ethclient.Client, auth *bind.TransactOpts) (ethCommon.Address, *types.Transaction, interface{}, error)) (ContractData, error) { - var contractData ContractData - log.Info("Deploying", "contract", name) - tx, err := c.CallAuth( - c.config.DeployGasLimit, - func(client *ethclient.Client, auth *bind.TransactOpts) (*types.Transaction, error) { - addr, tx, _, err := fn(client, auth) - if err != nil { - return nil, err - } - contractData.Address = addr - return tx, nil - }, - ) - if err != nil { - return contractData, fmt.Errorf(errStrDeploy, name, err) - } - log.Info("Waiting receipt", "tx", tx.Hash().Hex(), "contract", name) - contractData.Tx = tx - receipt, err := c.WaitReceipt(tx) - if err != nil { - return contractData, fmt.Errorf(errStrWaitReceipt, name, err) - } - contractData.Receipt = receipt - return contractData, nil -} - -// Call performs a read only Smart Contract method call. -func (c *Client) Call(fn func(*ethclient.Client) error) error { - return fn(c.client) -} - -// WaitReceipt will block until a transaction is confirmed. Internally it -// polls the state every 200 milliseconds. -func (c *Client) WaitReceipt(tx *types.Transaction) (*types.Receipt, error) { - return c.waitReceipt(context.TODO(), tx, c.ReceiptTimeout) -} - -// GetReceipt will check if a transaction is confirmed and return -// immediately, waiting at most 1 second and returning error if the transaction -// is still pending. -func (c *Client) GetReceipt(tx *types.Transaction) (*types.Receipt, error) { - ctx, cancel := context.WithTimeout(context.TODO(), 1*time.Second) - defer cancel() - return c.waitReceipt(ctx, tx, 0) -} - -func (c *Client) waitReceipt(ctx context.Context, tx *types.Transaction, timeout time.Duration) (*types.Receipt, error) { - var err error - var receipt *types.Receipt - - txid := tx.Hash() - log.Debug("Waiting for receipt", "tx", txid.Hex()) - - start := time.Now() - for { - receipt, err = c.client.TransactionReceipt(ctx, txid) - if receipt != nil || time.Since(start) >= timeout { - break - } - time.Sleep(c.config.IntervalReceiptLoop * time.Millisecond) - } +// +// Implementation +// - if receipt != nil && receipt.Status == types.ReceiptStatusFailed { - log.Error("Failed transaction", "tx", txid.Hex()) - return receipt, ErrReceiptStatusFailed - } - - if receipt == nil { - log.Debug("Pendingtransaction / Wait receipt timeout", "tx", txid.Hex(), "lasterr", err) - return receipt, ErrReceiptNotReceived - } - log.Debug("Successful transaction", "tx", txid.Hex()) - - return receipt, err -} - -// CurrentBlock returns the current block number in the blockchain -func (c *Client) CurrentBlock() (*big.Int, error) { - ctx, cancel := context.WithTimeout(context.TODO(), 1*time.Second) - defer cancel() - header, err := c.client.HeaderByNumber(ctx, nil) - if err != nil { - return nil, err - } - return header.Number, nil -} - -// HeaderByNumber internally calls ethclient.Client HeaderByNumber -func (c *Client) HeaderByNumber(ctx context.Context, number *big.Int) (*types.Header, error) { - return c.client.HeaderByNumber(ctx, number) +// Client is used to interact with Ethereum and the Hermez smart contracts. +type Client struct { + EthereumClient + AuctionClient + RollupClient } -// BlockByNumber internally calls ethclient.Client BlockByNumber and returns *common.Block -func (c *Client) BlockByNumber(ctx context.Context, number *big.Int) (*common.Block, error) { - block, err := c.client.BlockByNumber(ctx, number) - if err != nil { - return nil, err +// NewClient creates a new Client to interact with Ethereum and the Hermez smart contracts. +func NewClient(client *ethclient.Client, account *accounts.Account, ks *ethKeystore.KeyStore, config *EthereumConfig) *Client { + ethereumClient := NewEthereumClient(client, account, ks, config) + auctionClient := &AuctionClient{} + rollupCient := &RollupClient{} + return &Client{ + EthereumClient: *ethereumClient, + AuctionClient: *auctionClient, + RollupClient: *rollupCient, } - b := &common.Block{ - EthBlockNum: block.Number().Uint64(), - Timestamp: time.Unix(int64(block.Time()), 0), - Hash: block.Hash(), - } - return b, nil -} - -// ForgeCall send the *common.CallDataForge to the Forge method of the smart contract -func (c *Client) ForgeCall(callData *common.CallDataForge) ([]byte, error) { - // TODO this depends on the smart contracts, once are ready this will be updated - return nil, nil } diff --git a/eth/ethereum.go b/eth/ethereum.go new file mode 100644 index 0000000..48290cb --- /dev/null +++ b/eth/ethereum.go @@ -0,0 +1,244 @@ +package eth + +import ( + "context" + "fmt" + "math/big" + "time" + + "github.com/ethereum/go-ethereum/accounts" + "github.com/ethereum/go-ethereum/accounts/abi/bind" + ethKeystore "github.com/ethereum/go-ethereum/accounts/keystore" + ethCommon "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/core/types" + "github.com/ethereum/go-ethereum/ethclient" + "github.com/hermeznetwork/hermez-node/common" + "github.com/hermeznetwork/hermez-node/log" +) + +// EthereumInterface is the interface to Ethereum +type EthereumInterface interface { + EthCurrentBlock() (*big.Int, error) + EthHeaderByNumber(context.Context, *big.Int) (*types.Header, error) + EthBlockByNumber(context.Context, *big.Int) (*common.Block, error) +} + +var ( + // ErrAccountNil is used when the calls can not be made because the account is nil + ErrAccountNil = fmt.Errorf("Authorized calls can't be made when the account is nil") + // ErrReceiptStatusFailed is used when receiving a failed transaction + ErrReceiptStatusFailed = fmt.Errorf("receipt status is failed") + // ErrReceiptNotReceived is used when unable to retrieve a transaction + ErrReceiptNotReceived = fmt.Errorf("receipt not available") +) + +const ( + errStrDeploy = "deployment of %s failed: %w" + errStrWaitReceipt = "wait receipt of %s deploy failed: %w" + + // default values + defaultCallGasLimit = 300000 + defaultDeployGasLimit = 1000000 + defaultGasPriceDiv = 100 + defaultReceiptTimeout = 60 + defaultIntervalReceiptLoop = 200 +) + +// EthereumConfig defines the configuration parameters of the EthereumClient +type EthereumConfig struct { + CallGasLimit uint64 + DeployGasLimit uint64 + GasPriceDiv uint64 + ReceiptTimeout time.Duration // in seconds + IntervalReceiptLoop time.Duration // in milliseconds +} + +// EthereumClient is an ethereum client to call Smart Contract methods and check blockchain information. +type EthereumClient struct { + client *ethclient.Client + account *accounts.Account + ks *ethKeystore.KeyStore + ReceiptTimeout time.Duration + config *EthereumConfig +} + +// NewEthereumClient creates a EthereumClient instance. The account is not mandatory (it can +// be nil). If the account is nil, CallAuth will fail with ErrAccountNil. +func NewEthereumClient(client *ethclient.Client, account *accounts.Account, ks *ethKeystore.KeyStore, config *EthereumConfig) *EthereumClient { + if config == nil { + config = &EthereumConfig{ + CallGasLimit: defaultCallGasLimit, + DeployGasLimit: defaultDeployGasLimit, + GasPriceDiv: defaultGasPriceDiv, + ReceiptTimeout: defaultReceiptTimeout, + IntervalReceiptLoop: defaultIntervalReceiptLoop, + } + } + return &EthereumClient{client: client, account: account, ks: ks, ReceiptTimeout: config.ReceiptTimeout * time.Second, config: config} +} + +// BalanceAt retieves information about the default account +func (c *EthereumClient) BalanceAt(addr ethCommon.Address) (*big.Int, error) { + return c.client.BalanceAt(context.TODO(), addr, nil) +} + +// Account returns the underlying ethereum account +func (c *EthereumClient) Account() *accounts.Account { + return c.account +} + +// 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. +func (c *EthereumClient) CallAuth(gasLimit uint64, + fn func(*ethclient.Client, *bind.TransactOpts) (*types.Transaction, error)) (*types.Transaction, error) { + if c.account == nil { + return nil, ErrAccountNil + } + + gasPrice, err := c.client.SuggestGasPrice(context.Background()) + if err != nil { + return nil, 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.NewKeyStoreTransactor(c.ks, *c.account) + if err != nil { + return nil, err + } + auth.Value = big.NewInt(0) // in wei + if gasLimit == 0 { + auth.GasLimit = c.config.CallGasLimit // in units + } else { + auth.GasLimit = gasLimit // in units + } + auth.GasPrice = gasPrice + + tx, err := fn(c.client, auth) + if tx != nil { + log.Debugw("Transaction", "tx", tx.Hash().Hex(), "nonce", tx.Nonce()) + } + return tx, err +} + +// ContractData contains the contract data +type ContractData struct { + Address ethCommon.Address + Tx *types.Transaction + Receipt *types.Receipt +} + +// Deploy a smart contract. `name` is used to log deployment information. fn +// is a wrapper to the deploy function generated by abigen. In case of error, +// the returned `ContractData` may have some parameters filled depending on the +// kind of error that occurred. +func (c *EthereumClient) Deploy(name string, + fn func(c *ethclient.Client, auth *bind.TransactOpts) (ethCommon.Address, *types.Transaction, interface{}, error)) (ContractData, error) { + var contractData ContractData + log.Infow("Deploying", "contract", name) + tx, err := c.CallAuth( + c.config.DeployGasLimit, + func(client *ethclient.Client, auth *bind.TransactOpts) (*types.Transaction, error) { + addr, tx, _, err := fn(client, auth) + if err != nil { + return nil, err + } + contractData.Address = addr + return tx, nil + }, + ) + if err != nil { + return contractData, fmt.Errorf(errStrDeploy, name, err) + } + log.Infow("Waiting receipt", "tx", tx.Hash().Hex(), "contract", name) + contractData.Tx = tx + receipt, err := c.WaitReceipt(tx) + if err != nil { + return contractData, fmt.Errorf(errStrWaitReceipt, name, err) + } + contractData.Receipt = receipt + return contractData, nil +} + +// Call performs a read only Smart Contract method call. +func (c *EthereumClient) Call(fn func(*ethclient.Client) error) error { + return fn(c.client) +} + +// WaitReceipt will block until a transaction is confirmed. Internally it +// polls the state every 200 milliseconds. +func (c *EthereumClient) WaitReceipt(tx *types.Transaction) (*types.Receipt, error) { + return c.waitReceipt(context.TODO(), tx, c.ReceiptTimeout) +} + +// GetReceipt will check if a transaction is confirmed and return +// immediately, waiting at most 1 second and returning error if the transaction +// is still pending. +func (c *EthereumClient) GetReceipt(tx *types.Transaction) (*types.Receipt, error) { + ctx, cancel := context.WithTimeout(context.TODO(), 1*time.Second) + defer cancel() + return c.waitReceipt(ctx, tx, 0) +} + +func (c *EthereumClient) waitReceipt(ctx context.Context, tx *types.Transaction, timeout time.Duration) (*types.Receipt, error) { + var err error + var receipt *types.Receipt + + txid := tx.Hash() + log.Debugw("Waiting for receipt", "tx", txid.Hex()) + + start := time.Now() + for { + receipt, err = c.client.TransactionReceipt(ctx, txid) + if receipt != nil || time.Since(start) >= timeout { + break + } + time.Sleep(c.config.IntervalReceiptLoop * time.Millisecond) + } + + if receipt != nil && receipt.Status == types.ReceiptStatusFailed { + log.Errorw("Failed transaction", "tx", txid.Hex()) + return receipt, ErrReceiptStatusFailed + } + + if receipt == nil { + log.Debugw("Pendingtransaction / Wait receipt timeout", "tx", txid.Hex(), "lasterr", err) + return receipt, ErrReceiptNotReceived + } + log.Debugw("Successful transaction", "tx", txid.Hex()) + + return receipt, err +} + +// EthCurrentBlock returns the current block number in the blockchain +func (c *EthereumClient) EthCurrentBlock() (*big.Int, error) { + ctx, cancel := context.WithTimeout(context.TODO(), 1*time.Second) + defer cancel() + header, err := c.client.HeaderByNumber(ctx, nil) + if err != nil { + return nil, err + } + return header.Number, nil +} + +// EthHeaderByNumber internally calls ethclient.Client HeaderByNumber +func (c *EthereumClient) EthHeaderByNumber(ctx context.Context, number *big.Int) (*types.Header, error) { + return c.client.HeaderByNumber(ctx, number) +} + +// EthBlockByNumber internally calls ethclient.Client BlockByNumber and returns *common.Block +func (c *EthereumClient) EthBlockByNumber(ctx context.Context, number *big.Int) (*common.Block, error) { + block, err := c.client.BlockByNumber(ctx, number) + if err != nil { + return nil, err + } + b := &common.Block{ + EthBlockNum: block.Number().Uint64(), + Timestamp: time.Unix(int64(block.Time()), 0), + Hash: block.Hash(), + } + return b, nil +} diff --git a/eth/interface.go b/eth/interface.go deleted file mode 100644 index a53b9ff..0000000 --- a/eth/interface.go +++ /dev/null @@ -1,18 +0,0 @@ -package eth - -import ( - "context" - "math/big" - - "github.com/ethereum/go-ethereum/core/types" - "github.com/hermeznetwork/hermez-node/common" -) - -// ClientInterface is the eth Client interface used by hermez-node modules to -// interact with Ethereum Blockchain and smart contracts. -type ClientInterface interface { - CurrentBlock() (*big.Int, error) - HeaderByNumber(context.Context, *big.Int) (*types.Header, error) - BlockByNumber(context.Context, *big.Int) (*common.Block, error) - ForgeCall(*common.CallDataForge) ([]byte, error) -} diff --git a/eth/rollup.go b/eth/rollup.go new file mode 100644 index 0000000..fb90c93 --- /dev/null +++ b/eth/rollup.go @@ -0,0 +1,298 @@ +package eth + +import ( + "math/big" + + ethCommon "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/core/types" + "github.com/hermeznetwork/hermez-node/utils" + "github.com/iden3/go-iden3-crypto/babyjub" +) + +// RollupConstants are the constants of the Rollup Smart Contract +type RollupConstants struct { + // Maxim Deposit allowed + MaxAmountDeposit *big.Int + MaxAmountL2 *big.Int + MaxTokens uint32 + // maximum L1 transactions allowed to be queued for a batch + MaxL1Tx int + // maximum L1 user transactions allowed to be queued for a batch + MaxL1UserTx int + Rfield *big.Int + L1CoordinatorBytes int + L1UserBytes int + L2Bytes int +} + +// RollupVariables are the variables of the Rollup Smart Contract +type RollupVariables struct { + MaxTxVerifiers []int + TokenHEZ ethCommon.Address + GovernanceAddress ethCommon.Address + SafetyBot ethCommon.Address + ConsensusContract ethCommon.Address + WithdrawalContract ethCommon.Address + FeeAddToken *big.Int + ForgeL1Timeout int64 + FeeL1UserTx *big.Int +} + +// QueueStruct is the queue of L1Txs for a batch +//nolint:structcheck +type QueueStruct struct { + L1TxQueue [][]byte + CurrentIndex int64 + TotalL1TxFee *big.Int +} + +// RollupState represents the state of the Rollup in the Smart Contract +//nolint:structcheck,unused +type RollupState struct { + StateRoot *big.Int + ExitRoots []*big.Int + ExiNullifierMap map[[256 / 8]byte]bool + TokenList []ethCommon.Address + TokenMap map[ethCommon.Address]bool + mapL1TxQueue map[int64]QueueStruct + LastLTxBatch int64 + CurrentToForgeL1TxsNum int64 + LastToForgeL1TxsNum int64 + CurrentIdx int64 +} + +// RollupEventL1UserTx is an event of the Rollup Smart Contract +type RollupEventL1UserTx struct { + L1UserTx []byte + ToForgeL1TxsNum int64 + Position int +} + +// RollupEventAddToken is an event of the Rollup Smart Contract +type RollupEventAddToken struct { + Address ethCommon.Address + TokenID uint32 +} + +// RollupEventForgeBatch is an event of the Rollup Smart Contract +type RollupEventForgeBatch struct { + BatchNum int64 +} + +// RollupEventUpdateForgeL1Timeout is an event of the Rollup Smart Contract +type RollupEventUpdateForgeL1Timeout struct { + ForgeL1Timeout int64 +} + +// RollupEventUpdateFeeL1UserTx is an event of the Rollup Smart Contract +type RollupEventUpdateFeeL1UserTx struct { + FeeL1UserTx *big.Int +} + +// RollupEventUpdateFeeAddToken is an event of the Rollup Smart Contract +type RollupEventUpdateFeeAddToken struct { + FeeAddToken *big.Int +} + +// RollupEventUpdateTokenHez is an event of the Rollup Smart Contract +type RollupEventUpdateTokenHez struct { + TokenHEZ ethCommon.Address +} + +// RollupEventWithdraw is an event of the Rollup Smart Contract +type RollupEventWithdraw struct { + Idx int64 + NumExitRoot int +} + +// RollupEvents is the list of events in a block of the Rollup Smart Contract +type RollupEvents struct { //nolint:structcheck + L1UserTx []RollupEventL1UserTx + AddToken []RollupEventAddToken + ForgeBatch []RollupEventForgeBatch + UpdateForgeL1Timeout []RollupEventUpdateForgeL1Timeout + UpdateFeeL1UserTx []RollupEventUpdateFeeL1UserTx + UpdateFeeAddToken []RollupEventUpdateFeeAddToken + UpdateTokenHez []RollupEventUpdateTokenHez + Withdraw []RollupEventWithdraw +} + +// RollupForgeBatchArgs are the arguments to the ForgeBatch function in the Rollup Smart Contract +//nolint:structcheck,unused +type RollupForgeBatchArgs struct { + proofA [2]*big.Int + proofB [2][2]*big.Int + proofC [2]*big.Int + newLastIdx int64 + newStRoot *big.Int + newExitRoot *big.Int + // TODO: Replace compressedL1CoordinatorTx, l2TxsData, feeIdxCoordinator for vectors + compressedL1CoordinatorTx []byte + l2TxsData []byte + feeIdxCoordinator []byte + verifierIdx int64 + l1Batch bool +} + +// RollupInterface is the inteface to to Rollup Smart Contract +type RollupInterface interface { + // + // Smart Contract Methods + // + + // Public Functions + + RollupForgeBatch(*RollupForgeBatchArgs) (*types.Transaction, error) + RollupAddToken(tokenAddress ethCommon.Address) (*types.Transaction, error) + // RollupWithdrawSNARK() (*types.Transaction, error) // TODO (Not defined in Hermez.sol) + RollupWithdrawMerkleProof(tokenID int64, balance *big.Int, babyPubKey *babyjub.PublicKey, + numExitRoot int64, siblings []*big.Int, idx int64, instantWithdraw bool) (*types.Transaction, error) + RollupForceExit(fromIdx int64, amountF utils.Float16, tokenID int64) (*types.Transaction, error) + RollupForceTransfer(fromIdx int64, amountF utils.Float16, tokenID, toIdx int64) (*types.Transaction, error) + RollupCreateAccountDepositTransfer(babyPubKey babyjub.PublicKey, + loadAmountF, amountF utils.Float16, tokenID int64, toIdx int64) (*types.Transaction, error) + RollupDepositTransfer(fromIdx int64, loadAmountF, amountF utils.Float16, + tokenID int64, toIdx int64) (*types.Transaction, error) + RollupDeposit(fromIdx int64, loadAmountF utils.Float16, tokenID int64) (*types.Transaction, error) + RollupCreateAccountDepositFromRelayer(accountCreationAuthSig []byte, + babyPubKey babyjub.PublicKey, loadAmountF utils.Float16) (*types.Transaction, error) + RollupCreateAccountDeposit(babyPubKey babyjub.PublicKey, loadAmountF utils.Float16, + tokenID int64) (*types.Transaction, error) + + RollupGetTokenAddress(tokenID int64) (*ethCommon.Address, error) + RollupGetL1TxFromQueue(queue int64, position int64) ([]byte, error) + RollupGetQueue(queue int64) ([]byte, error) + + // Governance Public Functions + RollupUpdateForgeL1Timeout(newForgeL1Timeout int64) (*types.Transaction, error) + RollupUpdateFeeL1UserTx(newFeeL1UserTx *big.Int) (*types.Transaction, error) + RollupUpdateFeeAddToken(newFeeAddToken *big.Int) (*types.Transaction, error) + RollupUpdateTokensHEZ(newTokenHEZ ethCommon.Address) (*types.Transaction, error) + // RollupUpdateGovernance() (*types.Transaction, error) // TODO (Not defined in Hermez.sol) + + // + // Smart Contract Status + // + + RollupConstants() (*RollupConstants, error) + RollupEventsByBlock(blockNum int64) (*RollupEvents, *ethCommon.Hash, error) + RollupForgeBatchArgs(*types.Transaction) (*RollupForgeBatchArgs, error) +} + +// +// Implementation +// + +// RollupClient is the implementation of the interface to the Rollup Smart Contract in ethereum. +type RollupClient struct { +} + +// RollupForgeBatch is the interface to call the smart contract function +func (c *RollupClient) RollupForgeBatch(args *RollupForgeBatchArgs) (*types.Transaction, error) { + return nil, errTODO +} + +// RollupAddToken is the interface to call the smart contract function +func (c *RollupClient) RollupAddToken(tokenAddress ethCommon.Address) (*types.Transaction, error) { + return nil, errTODO +} + +// RollupWithdrawSNARK is the interface to call the smart contract function +// func (c *RollupClient) RollupWithdrawSNARK() (*types.Transaction, error) { // TODO (Not defined in Hermez.sol) +// return nil, errTODO +// } + +// RollupWithdrawMerkleProof is the interface to call the smart contract function +func (c *RollupClient) RollupWithdrawMerkleProof(tokenID int64, balance *big.Int, babyPubKey *babyjub.PublicKey, numExitRoot int64, siblings []*big.Int, idx int64, instantWithdraw bool) (*types.Transaction, error) { + return nil, errTODO +} + +// RollupForceExit is the interface to call the smart contract function +func (c *RollupClient) RollupForceExit(fromIdx int64, amountF utils.Float16, tokenID int64) (*types.Transaction, error) { + return nil, errTODO +} + +// RollupForceTransfer is the interface to call the smart contract function +func (c *RollupClient) RollupForceTransfer(fromIdx int64, amountF utils.Float16, tokenID, toIdx int64) (*types.Transaction, error) { + return nil, errTODO +} + +// RollupCreateAccountDepositTransfer is the interface to call the smart contract function +func (c *RollupClient) RollupCreateAccountDepositTransfer(babyPubKey babyjub.PublicKey, loadAmountF, amountF utils.Float16, tokenID int64, toIdx int64) (*types.Transaction, error) { + return nil, errTODO +} + +// RollupDepositTransfer is the interface to call the smart contract function +func (c *RollupClient) RollupDepositTransfer(fromIdx int64, loadAmountF, amountF utils.Float16, tokenID int64, toIdx int64) (*types.Transaction, error) { + return nil, errTODO +} + +// RollupDeposit is the interface to call the smart contract function +func (c *RollupClient) RollupDeposit(fromIdx int64, loadAmountF utils.Float16, tokenID int64) (*types.Transaction, error) { + return nil, errTODO +} + +// RollupCreateAccountDepositFromRelayer is the interface to call the smart contract function +func (c *RollupClient) RollupCreateAccountDepositFromRelayer(accountCreationAuthSig []byte, babyPubKey babyjub.PublicKey, loadAmountF utils.Float16) (*types.Transaction, error) { + return nil, errTODO +} + +// RollupCreateAccountDeposit is the interface to call the smart contract function +func (c *RollupClient) RollupCreateAccountDeposit(babyPubKey babyjub.PublicKey, loadAmountF utils.Float16, tokenID int64) (*types.Transaction, error) { + return nil, errTODO +} + +// RollupGetTokenAddress is the interface to call the smart contract function +func (c *RollupClient) RollupGetTokenAddress(tokenID int64) (*ethCommon.Address, error) { + return nil, errTODO +} + +// RollupGetL1TxFromQueue is the interface to call the smart contract function +func (c *RollupClient) RollupGetL1TxFromQueue(queue int64, position int64) ([]byte, error) { + return nil, errTODO +} + +// RollupGetQueue is the interface to call the smart contract function +func (c *RollupClient) RollupGetQueue(queue int64) ([]byte, error) { + return nil, errTODO +} + +// RollupUpdateForgeL1Timeout is the interface to call the smart contract function +func (c *RollupClient) RollupUpdateForgeL1Timeout(newForgeL1Timeout int64) (*types.Transaction, error) { + return nil, errTODO +} + +// RollupUpdateFeeL1UserTx is the interface to call the smart contract function +func (c *RollupClient) RollupUpdateFeeL1UserTx(newFeeL1UserTx *big.Int) (*types.Transaction, error) { + return nil, errTODO +} + +// RollupUpdateFeeAddToken is the interface to call the smart contract function +func (c *RollupClient) RollupUpdateFeeAddToken(newFeeAddToken *big.Int) (*types.Transaction, error) { + return nil, errTODO +} + +// RollupUpdateTokensHEZ is the interface to call the smart contract function +func (c *RollupClient) RollupUpdateTokensHEZ(newTokenHEZ ethCommon.Address) (*types.Transaction, error) { + return nil, errTODO +} + +// RollupUpdateGovernance is the interface to call the smart contract function +// func (c *RollupClient) RollupUpdateGovernance() (*types.Transaction, error) { // TODO (Not defined in Hermez.sol) +// return nil, errTODO +// } + +// RollupConstants returns the Constants of the Rollup Smart Contract +func (c *RollupClient) RollupConstants() (*RollupConstants, error) { + return nil, errTODO +} + +// RollupEventsByBlock returns the events in a block that happened in the Rollup Smart Contract +func (c *RollupClient) RollupEventsByBlock(blockNum int64) (*RollupEvents, *ethCommon.Hash, error) { + return nil, nil, errTODO +} + +// RollupForgeBatchArgs returns the arguments used in a ForgeBatch call in the Rollup Smart Contract in the given transaction +func (c *RollupClient) RollupForgeBatchArgs(transaction *types.Transaction) (*RollupForgeBatchArgs, error) { + return nil, errTODO +} diff --git a/synchronizer/synchronizer.go b/synchronizer/synchronizer.go index bd5d27a..f695254 100644 --- a/synchronizer/synchronizer.go +++ b/synchronizer/synchronizer.go @@ -86,11 +86,11 @@ func (s *Synchronizer) Sync() error { // TODO: Get this information from ethClient once it's implemented // for the moment we will get the latestblock - 20 as firstSavedBlock - latestBlock, err := s.ethClient.BlockByNumber(context.Background(), nil) + latestBlock, err := s.ethClient.EthBlockByNumber(context.Background(), nil) if err != nil { return err } - s.firstSavedBlock, err = s.ethClient.BlockByNumber(context.Background(), big.NewInt(int64(latestBlock.EthBlockNum-blocksToSync))) + s.firstSavedBlock, err = s.ethClient.EthBlockByNumber(context.Background(), big.NewInt(int64(latestBlock.EthBlockNum-blocksToSync))) if err != nil { return err } @@ -107,7 +107,7 @@ func (s *Synchronizer) Sync() error { lastSavedBlock = s.firstSavedBlock } else { // Get the latest block we have in History DB from blockchain to detect a reorg - ethBlock, err := s.ethClient.BlockByNumber(context.Background(), big.NewInt(int64(lastSavedBlock.EthBlockNum))) + ethBlock, err := s.ethClient.EthBlockByNumber(context.Background(), big.NewInt(int64(lastSavedBlock.EthBlockNum))) if err != nil { return err } @@ -130,7 +130,7 @@ func (s *Synchronizer) Sync() error { log.Debugf("Syncing...") // Get latest blockNum in blockchain - latestBlockNum, err := s.ethClient.CurrentBlock() + latestBlockNum, err := s.ethClient.EthCurrentBlock() if err != nil { return err } @@ -138,7 +138,7 @@ func (s *Synchronizer) Sync() error { log.Debugf("Blocks to sync: %v (lastSavedBlock: %v, latestBlock: %v)", latestBlockNum.Uint64()-lastSavedBlock.EthBlockNum, lastSavedBlock.EthBlockNum, latestBlockNum) for lastSavedBlock.EthBlockNum < latestBlockNum.Uint64() { - ethBlock, err := s.ethClient.BlockByNumber(context.Background(), big.NewInt(int64(lastSavedBlock.EthBlockNum+1))) + ethBlock, err := s.ethClient.EthBlockByNumber(context.Background(), big.NewInt(int64(lastSavedBlock.EthBlockNum+1))) if err != nil { return err } @@ -181,7 +181,7 @@ func (s *Synchronizer) reorg(uncleBlock *common.Block) error { // Iterate History DB and the blokchain looking for the latest valid block for !found && blockNum > s.firstSavedBlock.EthBlockNum { - header, err := s.ethClient.HeaderByNumber(context.Background(), big.NewInt(int64(blockNum))) + header, err := s.ethClient.EthHeaderByNumber(context.Background(), big.NewInt(int64(blockNum))) if err != nil { return err } @@ -247,7 +247,7 @@ func (s *Synchronizer) Status() (*Status, error) { status.CurrentBatch = lastSavedBatch // Get latest blockNum in blockchain - latestBlockNum, err := s.ethClient.CurrentBlock() + latestBlockNum, err := s.ethClient.EthCurrentBlock() if err != nil { return nil, err } diff --git a/test/ethclient.go b/test/ethclient.go index 82fde10..3cfed74 100644 --- a/test/ethclient.go +++ b/test/ethclient.go @@ -2,24 +2,29 @@ package test import ( "context" + "fmt" "math/big" "time" + ethCommon "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core/types" "github.com/hermeznetwork/hermez-node/common" + "github.com/hermeznetwork/hermez-node/eth" "github.com/hermeznetwork/hermez-node/log" + "github.com/hermeznetwork/hermez-node/utils" + "github.com/iden3/go-iden3-crypto/babyjub" ) -// Client implements the eth.IClient interface, allowing to manipulate the +// Client implements the eth.ClientInterface interface, allowing to manipulate the // values for testing, working with deterministic results. type Client struct { log bool blockNum *big.Int } -// NewTestEthClient returns a new test Client that implements the eth.IClient +// NewClient returns a new test Client that implements the eth.IClient // interface, at the given initialBlockNumber. -func NewTestEthClient(l bool, initialBlockNumber int64) *Client { +func NewClient(l bool, initialBlockNumber int64) *Client { return &Client{ log: l, blockNum: big.NewInt(initialBlockNumber), @@ -42,8 +47,8 @@ func (c *Client) SetBlockNum(blockNum *big.Int) { } } -// CurrentBlock returns the current blockNum -func (c *Client) CurrentBlock() (*big.Int, error) { +// EthCurrentBlock returns the current blockNum +func (c *Client) EthCurrentBlock() (*big.Int, error) { return c.blockNum, nil } @@ -54,15 +59,15 @@ func newHeader(number *big.Int) *types.Header { } } -// HeaderByNumber returns the *types.Header for the given block number in a +// EthHeaderByNumber returns the *types.Header for the given block number in a // deterministic way. -func (c *Client) HeaderByNumber(ctx context.Context, number *big.Int) (*types.Header, error) { +func (c *Client) EthHeaderByNumber(ctx context.Context, number *big.Int) (*types.Header, error) { return newHeader(number), nil } -// BlockByNumber returns the *common.Block for the given block number in a +// EthBlockByNumber returns the *common.Block for the given block number in a // deterministic way. -func (c *Client) BlockByNumber(ctx context.Context, number *big.Int) (*common.Block, error) { +func (c *Client) EthBlockByNumber(ctx context.Context, number *big.Int) (*common.Block, error) { header := newHeader(number) return &common.Block{ @@ -72,8 +77,265 @@ func (c *Client) BlockByNumber(ctx context.Context, number *big.Int) (*common.Bl }, nil } -// ForgeCall send the *common.CallDataForge to the Forge method of the mock -// smart contract -func (c *Client) ForgeCall(*common.CallDataForge) ([]byte, error) { - return nil, nil +var errTODO = fmt.Errorf("TODO: Not implemented yet") + +// +// Rollup +// + +// RollupForgeBatch is the interface to call the smart contract function +func (c *Client) RollupForgeBatch(*eth.RollupForgeBatchArgs) (*types.Transaction, error) { + return nil, errTODO +} + +// RollupAddToken is the interface to call the smart contract function +func (c *Client) RollupAddToken(tokenAddress ethCommon.Address) (*types.Transaction, error) { + return nil, errTODO +} + +// RollupWithdrawSNARK is the interface to call the smart contract function +// func (c *Client) RollupWithdrawSNARK() (*types.Transaction, error) { // TODO (Not defined in Hermez.sol) +// return nil, errTODO +// } + +// RollupWithdrawMerkleProof is the interface to call the smart contract function +func (c *Client) RollupWithdrawMerkleProof(tokenID int64, balance *big.Int, babyPubKey *babyjub.PublicKey, numExitRoot int64, siblings []*big.Int, idx int64, instantWithdraw bool) (*types.Transaction, error) { + return nil, errTODO +} + +// RollupForceExit is the interface to call the smart contract function +func (c *Client) RollupForceExit(fromIdx int64, amountF utils.Float16, tokenID int64) (*types.Transaction, error) { + return nil, errTODO +} + +// RollupForceTransfer is the interface to call the smart contract function +func (c *Client) RollupForceTransfer(fromIdx int64, amountF utils.Float16, tokenID, toIdx int64) (*types.Transaction, error) { + return nil, errTODO +} + +// RollupCreateAccountDepositTransfer is the interface to call the smart contract function +func (c *Client) RollupCreateAccountDepositTransfer(babyPubKey babyjub.PublicKey, loadAmountF, amountF utils.Float16, tokenID int64, toIdx int64) (*types.Transaction, error) { + return nil, errTODO +} + +// RollupDepositTransfer is the interface to call the smart contract function +func (c *Client) RollupDepositTransfer(fromIdx int64, loadAmountF, amountF utils.Float16, tokenID int64, toIdx int64) (*types.Transaction, error) { + return nil, errTODO +} + +// RollupDeposit is the interface to call the smart contract function +func (c *Client) RollupDeposit(fromIdx int64, loadAmountF utils.Float16, tokenID int64) (*types.Transaction, error) { + return nil, errTODO +} + +// RollupCreateAccountDepositFromRelayer is the interface to call the smart contract function +func (c *Client) RollupCreateAccountDepositFromRelayer(accountCreationAuthSig []byte, babyPubKey babyjub.PublicKey, loadAmountF utils.Float16) (*types.Transaction, error) { + return nil, errTODO +} + +// RollupCreateAccountDeposit is the interface to call the smart contract function +func (c *Client) RollupCreateAccountDeposit(babyPubKey babyjub.PublicKey, loadAmountF utils.Float16, tokenID int64) (*types.Transaction, error) { + return nil, errTODO +} + +// RollupGetTokenAddress is the interface to call the smart contract function +func (c *Client) RollupGetTokenAddress(tokenID int64) (*ethCommon.Address, error) { + return nil, errTODO +} + +// RollupGetL1TxFromQueue is the interface to call the smart contract function +func (c *Client) RollupGetL1TxFromQueue(queue int64, position int64) ([]byte, error) { + return nil, errTODO +} + +// RollupGetQueue is the interface to call the smart contract function +func (c *Client) RollupGetQueue(queue int64) ([]byte, error) { + return nil, errTODO +} + +// RollupUpdateForgeL1Timeout is the interface to call the smart contract function +func (c *Client) RollupUpdateForgeL1Timeout(newForgeL1Timeout int64) (*types.Transaction, error) { + return nil, errTODO +} + +// RollupUpdateFeeL1UserTx is the interface to call the smart contract function +func (c *Client) RollupUpdateFeeL1UserTx(newFeeL1UserTx *big.Int) (*types.Transaction, error) { + return nil, errTODO +} + +// RollupUpdateFeeAddToken is the interface to call the smart contract function +func (c *Client) RollupUpdateFeeAddToken(newFeeAddToken *big.Int) (*types.Transaction, error) { + return nil, errTODO +} + +// RollupUpdateTokensHEZ is the interface to call the smart contract function +func (c *Client) RollupUpdateTokensHEZ(newTokenHEZ ethCommon.Address) (*types.Transaction, error) { + return nil, errTODO +} + +// RollupUpdateGovernance is the interface to call the smart contract function +// func (c *Client) RollupUpdateGovernance() (*types.Transaction, error) { // TODO (Not defined in Hermez.sol) +// return nil, errTODO +// } + +// RollupConstants returns the Constants of the Rollup Smart Contract +func (c *Client) RollupConstants() (*eth.RollupConstants, error) { + return nil, errTODO +} + +// RollupEventsByBlock returns the events in a block that happened in the Rollup Smart Contract +func (c *Client) RollupEventsByBlock(blockNum int64) (*eth.RollupEvents, *ethCommon.Hash, error) { + return nil, nil, errTODO +} + +// RollupForgeBatchArgs returns the arguments used in a ForgeBatch call in the Rollup Smart Contract in the given transaction +func (c *Client) RollupForgeBatchArgs(transaction *types.Transaction) (*eth.RollupForgeBatchArgs, error) { + return nil, errTODO +} + +// +// Auction +// + +// AuctionSetSlotDeadline is the interface to call the smart contract function +func (c *Client) AuctionSetSlotDeadline(newDeadline uint8) (*types.Transaction, error) { + return nil, errTODO +} + +// AuctionGetSlotDeadline is the interface to call the smart contract function +func (c *Client) AuctionGetSlotDeadline() (uint8, error) { + return 0, errTODO +} + +// AuctionSetOpenAuctionSlots is the interface to call the smart contract function +func (c *Client) AuctionSetOpenAuctionSlots(newOpenAuctionSlots uint16) (*types.Transaction, error) { + return nil, errTODO +} + +// AuctionGetOpenAuctionSlots is the interface to call the smart contract function +func (c *Client) AuctionGetOpenAuctionSlots() (uint16, error) { return 0, errTODO } + +// AuctionSetClosedAuctionSlots is the interface to call the smart contract function +func (c *Client) AuctionSetClosedAuctionSlots(newClosedAuctionSlots uint16) (*types.Transaction, error) { + return nil, errTODO +} + +// AuctionGetClosedAuctionSlots is the interface to call the smart contract function +func (c *Client) AuctionGetClosedAuctionSlots() (uint16, error) { + return 0, errTODO +} + +// AuctionSetOutbidding is the interface to call the smart contract function +func (c *Client) AuctionSetOutbidding(newOutbidding uint8) (*types.Transaction, error) { + return nil, errTODO +} + +// AuctionGetOutbidding is the interface to call the smart contract function +func (c *Client) AuctionGetOutbidding() (uint8, error) { + return 0, errTODO +} + +// AuctionSetAllocationRatio is the interface to call the smart contract function +func (c *Client) AuctionSetAllocationRatio(newAllocationRatio [3]uint8) (*types.Transaction, error) { + return nil, errTODO +} + +// AuctionGetAllocationRatio is the interface to call the smart contract function +func (c *Client) AuctionGetAllocationRatio() ([3]uint8, error) { + return [3]uint8{}, errTODO +} + +// AuctionSetDonationAddress is the interface to call the smart contract function +func (c *Client) AuctionSetDonationAddress(newDonationAddress ethCommon.Address) (*types.Transaction, error) { + return nil, errTODO +} + +// AuctionGetDonationAddress is the interface to call the smart contract function +func (c *Client) AuctionGetDonationAddress() (*ethCommon.Address, error) { + return nil, errTODO +} + +// AuctionSetBootCoordinator is the interface to call the smart contract function +func (c *Client) AuctionSetBootCoordinator(newBootCoordinator ethCommon.Address) (*types.Transaction, error) { + return nil, errTODO +} + +// AuctionGetBootCoordinator is the interface to call the smart contract function +func (c *Client) AuctionGetBootCoordinator() (*ethCommon.Address, error) { + return nil, errTODO +} + +// AuctionChangeEpochMinBid is the interface to call the smart contract function +func (c *Client) AuctionChangeEpochMinBid(slotEpoch int64, newInitialMinBid *big.Int) (*types.Transaction, error) { + return nil, errTODO +} + +// AuctionRegisterCoordinator is the interface to call the smart contract function +func (c *Client) AuctionRegisterCoordinator(forgerAddress ethCommon.Address, URL string) (*types.Transaction, error) { + return nil, errTODO +} + +// AuctionIsRegisteredCoordinator is the interface to call the smart contract function +func (c *Client) AuctionIsRegisteredCoordinator(forgerAddress ethCommon.Address) (bool, error) { + return false, errTODO +} + +// AuctionUpdateCoordinatorInfo is the interface to call the smart contract function +func (c *Client) AuctionUpdateCoordinatorInfo(forgerAddress ethCommon.Address, newWithdrawAddress ethCommon.Address, newURL string) (*types.Transaction, error) { + return nil, errTODO +} + +// AuctionGetCurrentSlotNumber is the interface to call the smart contract function +func (c *Client) AuctionGetCurrentSlotNumber() (int64, error) { + return 0, errTODO +} + +// AuctionGetMinBidBySlot is the interface to call the smart contract function +func (c *Client) AuctionGetMinBidBySlot(slot int64) (*big.Int, error) { + return nil, errTODO +} + +// AuctionGetMinBidEpoch is the interface to call the smart contract function +func (c *Client) AuctionGetMinBidEpoch(epoch uint8) (*big.Int, error) { + return nil, errTODO +} + +// AuctionTokensReceived is the interface to call the smart contract function +// func (c *Client) AuctionTokensReceived(operator, from, to ethCommon.Address, amount *big.Int, userData, operatorData []byte) error { +// return errTODO +// } + +// AuctionBid is the interface to call the smart contract function +func (c *Client) AuctionBid(slot int64, bidAmount *big.Int, forger ethCommon.Address) (*types.Transaction, error) { + return nil, errTODO +} + +// AuctionMultiBid is the interface to call the smart contract function +func (c *Client) AuctionMultiBid(startingSlot int64, endingSlot int64, slotEpoch [6]bool, maxBid, closedMinBid, budget *big.Int, forger ethCommon.Address) (*types.Transaction, error) { + return nil, errTODO +} + +// AuctionCanForge is the interface to call the smart contract function +func (c *Client) AuctionCanForge(forger ethCommon.Address) (bool, error) { + return false, errTODO +} + +// AuctionForge is the interface to call the smart contract function +// func (c *Client) AuctionForge(forger ethCommon.Address) (bool, error) { +// return false, errTODO +// } + +// AuctionClaimHEZ is the interface to call the smart contract function +func (c *Client) AuctionClaimHEZ() (*types.Transaction, error) { + return nil, errTODO +} + +// AuctionConstants returns the Constants of the Auction Smart Contract +func (c *Client) AuctionConstants() (*eth.AuctionConstants, error) { + return nil, errTODO +} + +// AuctionEventsByBlock returns the events in a block that happened in the Auction Smart Contract +func (c *Client) AuctionEventsByBlock(blockNum int64) (*eth.AuctionEvents, *ethCommon.Hash, error) { + return nil, nil, errTODO } diff --git a/test/ethclient_test.go b/test/ethclient_test.go index a76e40b..4ea0de0 100644 --- a/test/ethclient_test.go +++ b/test/ethclient_test.go @@ -13,21 +13,21 @@ import ( func TestClientInterface(t *testing.T) { var c eth.ClientInterface - client := NewTestEthClient(true, 1000) + client := NewClient(true, 1000) c = client require.NotNil(t, c) } func TestEthClient(t *testing.T) { - c := NewTestEthClient(true, 1000) + c := NewClient(true, 1000) - block, err := c.BlockByNumber(context.TODO(), big.NewInt(3)) + block, err := c.EthBlockByNumber(context.TODO(), big.NewInt(3)) assert.Nil(t, err) assert.Equal(t, uint64(3), block.EthBlockNum) assert.Equal(t, time.Unix(3, 0), block.Timestamp) assert.Equal(t, "0x6b0ab5a7a0ebf5f05cef3b49bc7a9739de06469a4e05557d802ee828fdf5187e", block.Hash.Hex()) - header, err := c.HeaderByNumber(context.TODO(), big.NewInt(4)) + header, err := c.EthHeaderByNumber(context.TODO(), big.NewInt(4)) assert.Nil(t, err) assert.Equal(t, big.NewInt(4), header.Number) assert.Equal(t, uint64(4), header.Time)