Redo coordinator structure, connect API to node
- API:
- Modify the constructor so that hardcoded rollup constants don't need
to be passed (introduce a `Config` and use `configAPI` internally)
- Common:
- Update rollup constants with proper *big.Int when required
- Add BidCoordinator and Slot structs used by the HistoryDB and
Synchronizer.
- Add helper methods to AuctionConstants
- AuctionVariables: Add column `DefaultSlotSetBidSlotNum` (in the SQL
table: `default_slot_set_bid_slot_num`), which indicates at which
slotNum does the `DefaultSlotSetBid` specified starts applying.
- Config:
- Move coordinator exclusive configuration from the node config to the
coordinator config
- Coordinator:
- Reorganize the code towards having the goroutines started and stopped
from the coordinator itself instead of the node.
- Remove all stop and stopped channels, and use context.Context and
sync.WaitGroup instead.
- Remove BatchInfo setters and assing variables directly
- In ServerProof and ServerProofPool use context instead stop channel.
- Use message passing to notify the coordinator about sync updates and
reorgs
- Introduce the Pipeline, which can be started and stopped by the
Coordinator
- Introduce the TxManager, which manages ethereum transactions (the
TxManager is also in charge of making the forge call to the rollup
smart contract). The TxManager keeps ethereum transactions and:
1. Waits for the transaction to be accepted
2. Waits for the transaction to be confirmed for N blocks
- In forge logic, first prepare a batch and then wait for an available
server proof to have all work ready once the proof server is ready.
- Remove the `isForgeSequence` method which was querying the smart
contract, and instead use notifications sent by the Synchronizer to
figure out if it's forging time.
- Update test (which is a minimal test to manually see if the
coordinator starts)
- HistoryDB:
- Add method to get the number of batches in a slot (used to detect when
a slot has passed the bid winner forging deadline)
- Add method to get the best bid and associated coordinator of a slot
(used to detect the forgerAddress that can forge the slot)
- General:
- Rename some instances of `currentBlock` to `lastBlock` to be more
clear.
- Node:
- Connect the API to the node and call the methods to update cached
state when the sync advances blocks.
- Call methods to update Coordinator state when the sync advances blocks
and finds reorgs.
- Synchronizer:
- Add Auction field in the Stats, which contain the current slot with
info about highest bidder and other related info required to know who
can forge in the current block.
- Better organization of cached state:
- On Sync, update the internal cached state
- On Init or Reorg, load the state from HistoryDB into the
internal cached state.
4 years ago Redo coordinator structure, connect API to node
- API:
- Modify the constructor so that hardcoded rollup constants don't need
to be passed (introduce a `Config` and use `configAPI` internally)
- Common:
- Update rollup constants with proper *big.Int when required
- Add BidCoordinator and Slot structs used by the HistoryDB and
Synchronizer.
- Add helper methods to AuctionConstants
- AuctionVariables: Add column `DefaultSlotSetBidSlotNum` (in the SQL
table: `default_slot_set_bid_slot_num`), which indicates at which
slotNum does the `DefaultSlotSetBid` specified starts applying.
- Config:
- Move coordinator exclusive configuration from the node config to the
coordinator config
- Coordinator:
- Reorganize the code towards having the goroutines started and stopped
from the coordinator itself instead of the node.
- Remove all stop and stopped channels, and use context.Context and
sync.WaitGroup instead.
- Remove BatchInfo setters and assing variables directly
- In ServerProof and ServerProofPool use context instead stop channel.
- Use message passing to notify the coordinator about sync updates and
reorgs
- Introduce the Pipeline, which can be started and stopped by the
Coordinator
- Introduce the TxManager, which manages ethereum transactions (the
TxManager is also in charge of making the forge call to the rollup
smart contract). The TxManager keeps ethereum transactions and:
1. Waits for the transaction to be accepted
2. Waits for the transaction to be confirmed for N blocks
- In forge logic, first prepare a batch and then wait for an available
server proof to have all work ready once the proof server is ready.
- Remove the `isForgeSequence` method which was querying the smart
contract, and instead use notifications sent by the Synchronizer to
figure out if it's forging time.
- Update test (which is a minimal test to manually see if the
coordinator starts)
- HistoryDB:
- Add method to get the number of batches in a slot (used to detect when
a slot has passed the bid winner forging deadline)
- Add method to get the best bid and associated coordinator of a slot
(used to detect the forgerAddress that can forge the slot)
- General:
- Rename some instances of `currentBlock` to `lastBlock` to be more
clear.
- Node:
- Connect the API to the node and call the methods to update cached
state when the sync advances blocks.
- Call methods to update Coordinator state when the sync advances blocks
and finds reorgs.
- Synchronizer:
- Add Auction field in the Stats, which contain the current slot with
info about highest bidder and other related info required to know who
can forge in the current block.
- Better organization of cached state:
- On Sync, update the internal cached state
- On Init or Reorg, load the state from HistoryDB into the
internal cached state.
4 years ago Update missing parts, improve til, and more
- Node
- Updated configuration to initialize the interface to all the smart
contracts
- Common
- Moved BlockData and BatchData types to common so that they can be
shared among: historydb, til and synchronizer
- Remove hash.go (it was never used)
- Remove slot.go (it was never used)
- Remove smartcontractparams.go (it was never used, and appropriate
structs are defined in `eth/`)
- Comment state / status method until requirements of this method are
properly defined, and move it to Synchronizer
- Synchronizer
- Simplify `Sync` routine to only sync one block per call, and return
useful information.
- Use BlockData and BatchData from common
- Check that events belong to the expected block hash
- In L1Batch, query L1UserTxs from HistoryDB
- Fill ERC20 token information
- Test AddTokens with test.Client
- HistryDB
- Use BlockData and BatchData from common
- Add `GetAllTokens` method
- Uncomment and update GetL1UserTxs (with corresponding tests)
- Til
- Rename all instances of RegisterToken to AddToken (to follow the smart
contract implementation naming)
- Use BlockData and BatchData from common
- Move testL1CoordinatorTxs and testL2Txs to a separate struct
from BatchData in Context
- Start Context with BatchNum = 1 (which the protocol defines to be the
first batchNum)
- In every Batch, set StateRoot and ExitRoot to a non-nil big.Int
(zero).
- In all L1Txs, if LoadAmount is not used, set it to 0; if Amount is not
used, set it to 0; so that no *big.Int is nil.
- In L1UserTx, don't set BatchNum, because when L1UserTxs are created
and obtained by the synchronizer, the BatchNum is not known yet (it's
a synchronizer job to set it)
- In L1UserTxs, set `UserOrigin` and set `ToForgeL1TxsNum`.
4 years ago Update missing parts, improve til, and more
- Node
- Updated configuration to initialize the interface to all the smart
contracts
- Common
- Moved BlockData and BatchData types to common so that they can be
shared among: historydb, til and synchronizer
- Remove hash.go (it was never used)
- Remove slot.go (it was never used)
- Remove smartcontractparams.go (it was never used, and appropriate
structs are defined in `eth/`)
- Comment state / status method until requirements of this method are
properly defined, and move it to Synchronizer
- Synchronizer
- Simplify `Sync` routine to only sync one block per call, and return
useful information.
- Use BlockData and BatchData from common
- Check that events belong to the expected block hash
- In L1Batch, query L1UserTxs from HistoryDB
- Fill ERC20 token information
- Test AddTokens with test.Client
- HistryDB
- Use BlockData and BatchData from common
- Add `GetAllTokens` method
- Uncomment and update GetL1UserTxs (with corresponding tests)
- Til
- Rename all instances of RegisterToken to AddToken (to follow the smart
contract implementation naming)
- Use BlockData and BatchData from common
- Move testL1CoordinatorTxs and testL2Txs to a separate struct
from BatchData in Context
- Start Context with BatchNum = 1 (which the protocol defines to be the
first batchNum)
- In every Batch, set StateRoot and ExitRoot to a non-nil big.Int
(zero).
- In all L1Txs, if LoadAmount is not used, set it to 0; if Amount is not
used, set it to 0; so that no *big.Int is nil.
- In L1UserTx, don't set BatchNum, because when L1UserTxs are created
and obtained by the synchronizer, the BatchNum is not known yet (it's
a synchronizer job to set it)
- In L1UserTxs, set `UserOrigin` and set `ToForgeL1TxsNum`.
4 years ago Redo coordinator structure, connect API to node
- API:
- Modify the constructor so that hardcoded rollup constants don't need
to be passed (introduce a `Config` and use `configAPI` internally)
- Common:
- Update rollup constants with proper *big.Int when required
- Add BidCoordinator and Slot structs used by the HistoryDB and
Synchronizer.
- Add helper methods to AuctionConstants
- AuctionVariables: Add column `DefaultSlotSetBidSlotNum` (in the SQL
table: `default_slot_set_bid_slot_num`), which indicates at which
slotNum does the `DefaultSlotSetBid` specified starts applying.
- Config:
- Move coordinator exclusive configuration from the node config to the
coordinator config
- Coordinator:
- Reorganize the code towards having the goroutines started and stopped
from the coordinator itself instead of the node.
- Remove all stop and stopped channels, and use context.Context and
sync.WaitGroup instead.
- Remove BatchInfo setters and assing variables directly
- In ServerProof and ServerProofPool use context instead stop channel.
- Use message passing to notify the coordinator about sync updates and
reorgs
- Introduce the Pipeline, which can be started and stopped by the
Coordinator
- Introduce the TxManager, which manages ethereum transactions (the
TxManager is also in charge of making the forge call to the rollup
smart contract). The TxManager keeps ethereum transactions and:
1. Waits for the transaction to be accepted
2. Waits for the transaction to be confirmed for N blocks
- In forge logic, first prepare a batch and then wait for an available
server proof to have all work ready once the proof server is ready.
- Remove the `isForgeSequence` method which was querying the smart
contract, and instead use notifications sent by the Synchronizer to
figure out if it's forging time.
- Update test (which is a minimal test to manually see if the
coordinator starts)
- HistoryDB:
- Add method to get the number of batches in a slot (used to detect when
a slot has passed the bid winner forging deadline)
- Add method to get the best bid and associated coordinator of a slot
(used to detect the forgerAddress that can forge the slot)
- General:
- Rename some instances of `currentBlock` to `lastBlock` to be more
clear.
- Node:
- Connect the API to the node and call the methods to update cached
state when the sync advances blocks.
- Call methods to update Coordinator state when the sync advances blocks
and finds reorgs.
- Synchronizer:
- Add Auction field in the Stats, which contain the current slot with
info about highest bidder and other related info required to know who
can forge in the current block.
- Better organization of cached state:
- On Sync, update the internal cached state
- On Init or Reorg, load the state from HistoryDB into the
internal cached state.
4 years ago Update coordinator, call all api update functions
- Common:
- Rename Block.EthBlockNum to Block.Num to avoid unneeded repetition
- API:
- Add UpdateNetworkInfoBlock to update just block information, to be
used when the node is not yet synchronized
- Node:
- Call API.UpdateMetrics and UpdateRecommendedFee in a loop, with
configurable time intervals
- Synchronizer:
- When mapping events by TxHash, use an array to support the possibility
of multiple calls of the same function happening in the same
transaction (for example, a smart contract in a single transaction
could call withdraw with delay twice, which would generate 2 withdraw
events, and 2 deposit events).
- In Stats, keep entire LastBlock instead of just the blockNum
- In Stats, add lastL1BatchBlock
- Test Stats and SCVars
- Coordinator:
- Enable writing the BatchInfo in every step of the pipeline to disk
(with JSON text files) for debugging purposes.
- Move the Pipeline functionality from the Coordinator to its own struct
(Pipeline)
- Implement shouldL1lL2Batch
- In TxManager, implement logic to perform several attempts when doing
ethereum node RPC calls before considering the error. (Both for calls
to forgeBatch and transaction receipt)
- In TxManager, reorganize the flow and note the specific points in
which actions are made when err != nil
- HistoryDB:
- Implement GetLastL1BatchBlockNum: returns the blockNum of the latest
forged l1Batch, to help the coordinator decide when to forge an
L1Batch.
- EthereumClient and test.Client:
- Update EthBlockByNumber to return the last block when the passed
number is -1.
4 years ago Update missing parts, improve til, and more
- Node
- Updated configuration to initialize the interface to all the smart
contracts
- Common
- Moved BlockData and BatchData types to common so that they can be
shared among: historydb, til and synchronizer
- Remove hash.go (it was never used)
- Remove slot.go (it was never used)
- Remove smartcontractparams.go (it was never used, and appropriate
structs are defined in `eth/`)
- Comment state / status method until requirements of this method are
properly defined, and move it to Synchronizer
- Synchronizer
- Simplify `Sync` routine to only sync one block per call, and return
useful information.
- Use BlockData and BatchData from common
- Check that events belong to the expected block hash
- In L1Batch, query L1UserTxs from HistoryDB
- Fill ERC20 token information
- Test AddTokens with test.Client
- HistryDB
- Use BlockData and BatchData from common
- Add `GetAllTokens` method
- Uncomment and update GetL1UserTxs (with corresponding tests)
- Til
- Rename all instances of RegisterToken to AddToken (to follow the smart
contract implementation naming)
- Use BlockData and BatchData from common
- Move testL1CoordinatorTxs and testL2Txs to a separate struct
from BatchData in Context
- Start Context with BatchNum = 1 (which the protocol defines to be the
first batchNum)
- In every Batch, set StateRoot and ExitRoot to a non-nil big.Int
(zero).
- In all L1Txs, if LoadAmount is not used, set it to 0; if Amount is not
used, set it to 0; so that no *big.Int is nil.
- In L1UserTx, don't set BatchNum, because when L1UserTxs are created
and obtained by the synchronizer, the BatchNum is not known yet (it's
a synchronizer job to set it)
- In L1UserTxs, set `UserOrigin` and set `ToForgeL1TxsNum`.
4 years ago |
|
package config
import ( "fmt" "io/ioutil" "time"
"github.com/BurntSushi/toml" ethCommon "github.com/ethereum/go-ethereum/common" "github.com/hermeznetwork/hermez-node/common" "github.com/hermeznetwork/tracerr" "github.com/iden3/go-iden3-crypto/babyjub" "gopkg.in/go-playground/validator.v9" )
// Duration is a wrapper type that parses time duration from text.
type Duration struct { time.Duration `validate:"required"` }
// UnmarshalText unmarshalls time duration from text.
func (d *Duration) UnmarshalText(data []byte) error { duration, err := time.ParseDuration(string(data)) if err != nil { return tracerr.Wrap(err) } d.Duration = duration return nil }
// ServerProof is the server proof configuration data.
type ServerProof struct { // URL is the server proof API URL
URL string `validate:"required"` }
// Coordinator is the coordinator specific configuration.
type Coordinator struct { // ForgerAddress is the address under which this coordinator is forging
ForgerAddress ethCommon.Address `validate:"required"` // FeeAccount is the Hermez account that the coordinator uses to receive fees
FeeAccount struct { // Address is the ethereum address of the account to receive fees
Address ethCommon.Address `validate:"required"` // BJJ is the baby jub jub public key of the account to receive fees
BJJ babyjub.PublicKeyComp `validate:"required"` } `validate:"required"` // ConfirmBlocks is the number of confirmation blocks to wait for sent
// ethereum transactions before forgetting about them
ConfirmBlocks int64 `validate:"required"` // L1BatchTimeoutPerc is the portion of the range before the L1Batch
// timeout that will trigger a schedule to forge an L1Batch
L1BatchTimeoutPerc float64 `validate:"required"` // ProofServerPollInterval is the waiting interval between polling the
// ProofServer while waiting for a particular status
ProofServerPollInterval Duration `validate:"required"` // ForgeRetryInterval is the waiting interval between calls forge a
// batch after an error
ForgeRetryInterval Duration `validate:"required"` // SyncRetryInterval is the waiting interval between calls to the main
// handler of a synced block after an error
SyncRetryInterval Duration `validate:"required"` // L2DB is the DB that holds the pool of L2Txs
L2DB struct { // SafetyPeriod is the number of batches after which
// non-pending L2Txs are deleted from the pool
SafetyPeriod common.BatchNum `validate:"required"` // MaxTxs is the number of L2Txs that once reached triggers
// deletion of old L2Txs
MaxTxs uint32 `validate:"required"` // TTL is the Time To Live for L2Txs in the pool. Once MaxTxs
// L2Txs is reached, L2Txs older than TTL will be deleted.
TTL Duration `validate:"required"` // PurgeBatchDelay is the delay between batches to purge outdated transactions
PurgeBatchDelay int64 `validate:"required"` // InvalidateBatchDelay is the delay between batches to mark invalid transactions
InvalidateBatchDelay int64 `validate:"required"` // PurgeBlockDelay is the delay between blocks to purge outdated transactions
PurgeBlockDelay int64 `validate:"required"` // InvalidateBlockDelay is the delay between blocks to mark invalid transactions
InvalidateBlockDelay int64 `validate:"required"` } `validate:"required"` TxSelector struct { // Path where the TxSelector StateDB is stored
Path string `validate:"required"` } `validate:"required"` BatchBuilder struct { // Path where the BatchBuilder StateDB is stored
Path string `validate:"required"` } `validate:"required"` ServerProofs []ServerProof `validate:"required"` Circuit struct { // VerifierIdx uint8 `validate:"required"`
// MaxTx is the maximum number of txs supported by the circuit
MaxTx int64 `validate:"required"` // NLevels is the maximum number of merkle tree levels
// supported by the circuit
NLevels int64 `validate:"required"` } `validate:"required"` EthClient struct { // CallGasLimit is the default gas limit set for ethereum
// calls, except for methods where a particular gas limit is
// harcoded because it's known to be a big value
CallGasLimit uint64 `validate:"required"` // GasPriceDiv is the gas price division
GasPriceDiv uint64 `validate:"required"` // CheckLoopInterval is the waiting interval between receipt
// checks of ethereum transactions in the TxManager
CheckLoopInterval Duration `validate:"required"` // Attempts is the number of attempts to do an eth client RPC
// call before giving up
Attempts int `validate:"required"` // AttemptsDelay is delay between attempts do do an eth client
// RPC call
AttemptsDelay Duration `validate:"required"` // Keystore is the ethereum keystore where private keys are kept
Keystore struct { // Path to the keystore
Path string `validate:"required"` // Password used to decrypt the keys in the keystore
Password string `validate:"required"` } `validate:"required"` } `validate:"required"` API struct { // Coordinator enables the coordinator API endpoints
Coordinator bool } `validate:"required"` Debug struct { // BatchPath if set, specifies the path where batchInfo is stored
// in JSON in every step/update of the pipeline
BatchPath string // LightScrypt if set, uses light parameters for the ethereum
// keystore encryption algorithm.
LightScrypt bool } }
// Node is the hermez node configuration.
type Node struct { PriceUpdater struct { // Interval between price updater calls
Interval Duration `valudate:"required"` // URL of the token prices provider
URL string `valudate:"required"` // Type of the API of the token prices provider
Type string `valudate:"required"` } `validate:"required"` StateDB struct { // Path where the synchronizer StateDB is stored
Path string `validate:"required"` // Keep is the number of checkpoints to keep
Keep int `validate:"required"` } `validate:"required"` PostgreSQL struct { // Port of the PostgreSQL server
Port int `validate:"required"` // Host of the PostgreSQL server
Host string `validate:"required"` // User of the PostgreSQL server
User string `validate:"required"` // Password of the PostgreSQL server
Password string `validate:"required"` // Name of the PostgreSQL server database
Name string `validate:"required"` } `validate:"required"` Web3 struct { // URL is the URL of the web3 ethereum-node RPC server
URL string `validate:"required"` } `validate:"required"` Synchronizer struct { // SyncLoopInterval is the interval between attempts to
// synchronize a new block from an ethereum node
SyncLoopInterval Duration `validate:"required"` // StatsRefreshPeriod is the interval between updates of the
// synchronizer state Eth parameters (`Eth.LastBlock` and
// `Eth.LastBatch`). This value only affects the reported % of
// synchronization of blocks and batches, nothing else.
StatsRefreshPeriod Duration `validate:"required"` } `validate:"required"` SmartContracts struct { // Rollup is the address of the Hermez.sol smart contract
Rollup ethCommon.Address `validate:"required"` // Rollup is the address of the HermezAuctionProtocol.sol smart
// contract
Auction ethCommon.Address `validate:"required"` // WDelayer is the address of the WithdrawalDelayer.sol smart
// contract
WDelayer ethCommon.Address `validate:"required"` // TokenHEZ is the address of the HEZTokenFull.sol smart
// contract
TokenHEZ ethCommon.Address `validate:"required"` // TokenHEZName is the name of the HEZ token deployed at
// TokenHEZ address
TokenHEZName string `validate:"required"` } `validate:"required"` API struct { // Address where the API will listen if set
Address string // Explorer enables the Explorer API endpoints
Explorer bool // UpdateMetricsInterval is the interval between updates of the
// API metrics
UpdateMetricsInterval Duration // UpdateRecommendedFeeInterval is the interval between updates of the
// recommended fees
UpdateRecommendedFeeInterval Duration // Maximum concurrent connections allowed between API and SQL
MaxSQLConnections int `validate:"required"` // SQLConnectionTimeout is the maximum amount of time that an API request
// can wait to stablish a SQL connection
SQLConnectionTimeout Duration } `validate:"required"` Debug struct { // APIAddress is the address where the debugAPI will listen if
// set
APIAddress string // MeddlerLogs enables meddler debug mode, where unused columns and struct
// fields will be logged
MeddlerLogs bool } Coordinator Coordinator `validate:"-"` }
// Load loads a generic config.
func Load(path string, cfg interface{}) error { bs, err := ioutil.ReadFile(path) //nolint:gosec
if err != nil { return tracerr.Wrap(err) } cfgToml := string(bs) if _, err := toml.Decode(cfgToml, cfg); err != nil { return tracerr.Wrap(err) } return nil }
// LoadCoordinator loads the Coordinator configuration from path.
func LoadCoordinator(path string) (*Node, error) { var cfg Node if err := Load(path, &cfg); err != nil { return nil, tracerr.Wrap(fmt.Errorf("error loading node configuration file: %w", err)) } validate := validator.New() if err := validate.Struct(cfg); err != nil { return nil, tracerr.Wrap(fmt.Errorf("error validating configuration file: %w", err)) } if err := validate.Struct(cfg.Coordinator); err != nil { return nil, tracerr.Wrap(fmt.Errorf("error validating configuration file: %w", err)) } return &cfg, nil }
// LoadNode loads the Node configuration from path.
func LoadNode(path string) (*Node, error) { var cfg Node if err := Load(path, &cfg); err != nil { return nil, tracerr.Wrap(fmt.Errorf("error loading node configuration file: %w", err)) } validate := validator.New() if err := validate.Struct(cfg); err != nil { return nil, tracerr.Wrap(fmt.Errorf("error validating configuration file: %w", err)) } return &cfg, nil }
|