arnaucube
arnaucube/hermez-nodePublic Self-hosted repository
hermez-node/coordinator/coordinator.go
coordinator/coordinator.goRaw
  1package coordinator
  2
  3import (
  4	"time"
  5
  6	ethCommon "github.com/ethereum/go-ethereum/common"
  7	"github.com/hermeznetwork/hermez-node/batchbuilder"
  8	"github.com/hermeznetwork/hermez-node/common"
  9	"github.com/hermeznetwork/hermez-node/eth"
 10	"github.com/hermeznetwork/hermez-node/txselector"
 11	kvdb "github.com/iden3/go-merkletree/db"
 12	"github.com/iden3/go-merkletree/db/memory"
 13)
 14
 15// CoordinatorConfig contains the Coordinator configuration
 16type CoordinatorConfig struct {
 17	ForgerAddress ethCommon.Address
 18}
 19
 20// Coordinator implements the Coordinator type
 21type Coordinator struct {
 22	config CoordinatorConfig
 23
 24	batchNum        uint64
 25	batchQueue      *BatchQueue
 26	serverProofPool ServerProofPool
 27
 28	// synchronizer *synchronizer.Synchronizer
 29	txsel        *txselector.TxSelector
 30	batchBuilder *batchbuilder.BatchBuilder
 31
 32	ethClient  *eth.EthClient
 33	ethTxStore kvdb.Storage
 34}
 35
 36// NewCoordinator creates a new Coordinator
 37func NewCoordinator() *Coordinator { // once synchronizer is ready, synchronizer.Synchronizer will be passed as parameter here
 38	var c *Coordinator
 39	c.ethClient = eth.NewEthClient() // TBD
 40	c.ethTxStore = memory.NewMemoryStorage()
 41	return c
 42}
 43
 44// Start starts the Coordinator service
 45func (c *Coordinator) Start() {
 46	// TODO TBD note: the sequences & loops & errors & logging & goroutines
 47	// & channels approach still needs to be defined, the current code is a
 48	// wip draft
 49
 50	// TBD: goroutines strategy
 51
 52	// if in Forge Sequence:
 53	if c.isForgeSequence() {
 54		// c.batchNum = c.synchronizer.LastBatchNum()
 55		_ = c.txsel.Reset(c.batchNum)
 56		_ = c.batchBuilder.Reset(c.batchNum, true)
 57		c.batchQueue = NewBatchQueue()
 58		go func() {
 59			for {
 60				_ = c.forgeSequence()
 61				time.Sleep(1 * time.Second)
 62			}
 63		}()
 64		go func() {
 65			for {
 66				_ = c.proveSequence()
 67				time.Sleep(1 * time.Second)
 68			}
 69		}()
 70		go func() {
 71			for {
 72				_ = c.forgeConfirmationSequence()
 73				time.Sleep(1 * time.Second)
 74			}
 75		}()
 76	}
 77}
 78
 79func (c *Coordinator) forgeSequence() error {
 80	// TODO once synchronizer has this method ready:
 81	// If there's been a reorg, handle it
 82	// handleReorg() function decides if the reorg must restart the pipeline or not
 83	// if c.synchronizer.Reorg():
 84	_ = c.handleReorg()
 85
 86	// 0. If there's an available server proof: Start pipeline for batchNum = batchNum + 1
 87	serverProofInfo, err := c.serverProofPool.GetNextAvailable() // blocking call, returns when a server proof is available
 88	if err != nil {
 89		return err
 90	}
 91
 92	// remove transactions from the pool that have been there for too long
 93	err = c.purgeRemoveByTimeout()
 94	if err != nil {
 95		return err
 96	}
 97
 98	c.batchNum = c.batchNum + 1
 99	batchInfo := NewBatchInfo(c.batchNum, serverProofInfo) // to accumulate metadata of the batch
100
101	var l2Txs []common.PoolL2Tx
102	// var feesInfo
103	var l1UserTxsExtra, l1OperatorTxs []common.L1Tx
104	// 1. Decide if we forge L2Tx or L1+L2Tx
105	if c.shouldL1L2Batch() {
106		// 2a: L1+L2 txs
107		// l1UserTxs, toForgeL1TxsNumber := c.synchronizer.GetNextL1UserTxs() // TODO once synchronizer is ready, uncomment
108		var l1UserTxs []common.L1Tx = nil                                                             // tmp, depends on synchronizer
109		l1UserTxsExtra, l1OperatorTxs, l2Txs, err = c.txsel.GetL1L2TxSelection(c.batchNum, l1UserTxs) // TODO once feesInfo is added to method return, add the var
110		if err != nil {
111			return err
112		}
113	} else {
114		// 2b: only L2 txs
115		l2Txs, err = c.txsel.GetL2TxSelection(c.batchNum) // TODO once feesInfo is added to method return, add the var
116		if err != nil {
117			return err
118		}
119		l1UserTxsExtra = nil
120		l1OperatorTxs = nil
121	}
122
123	// Run purger to invalidate transactions that become invalid beause of
124	// the l2Txs selected.  Will mark as invalid the txs that have a
125	// (fromIdx, nonce) which already appears in the selected txs (includes
126	// all the nonces smaller than the current one)
127	err = c.purgeInvalidDueToL2TxsSelection(l2Txs)
128	if err != nil {
129		return err
130	}
131
132	// 3.  Save metadata from TxSelector output for BatchNum
133	batchInfo.SetTxsInfo(l1UserTxsExtra, l1OperatorTxs, l2Txs) // TODO feesInfo
134
135	// 4. Call BatchBuilder with TxSelector output
136	configBatch := batchbuilder.ConfigBatch{
137		ForgerAddress: c.config.ForgerAddress,
138	}
139	zkInputs, err := c.batchBuilder.BuildBatch(configBatch, l1UserTxsExtra, l1OperatorTxs, l2Txs, nil) // TODO []common.TokenID --> feesInfo
140	if err != nil {
141		return err
142	}
143
144	// 5. Save metadata from BatchBuilder output for BatchNum
145	batchInfo.SetZKInputs(zkInputs)
146
147	// 6. Call an idle server proof with BatchBuilder output, save server proof info for batchNum
148	err = batchInfo.serverProof.CalculateProof(zkInputs)
149	if err != nil {
150		return err
151	}
152	c.batchQueue.Push(&batchInfo)
153
154	return nil
155}
156
157// proveSequence gets the generated zkProof & sends it to the SmartContract
158func (c *Coordinator) proveSequence() error {
159	batchInfo := c.batchQueue.Pop()
160	if batchInfo == nil {
161		// no batches in queue, return
162		return common.ErrBatchQueueEmpty
163	}
164	serverProofInfo := batchInfo.serverProof
165	proof, err := serverProofInfo.GetProof() // blocking call, until not resolved don't continue. Returns when the proof server has calculated the proof
166	if err != nil {
167		return err
168	}
169	batchInfo.SetProof(proof)
170	callData := c.prepareCallDataForge(batchInfo)
171	_, err = c.ethClient.ForgeCall(callData)
172	if err != nil {
173		return err
174	}
175	// TODO once tx data type is defined, store ethTx (returned by ForgeCall)
176	// TBD if use ethTxStore as a disk k-v database, or use a Queue
177	// tx, err := c.ethTxStore.NewTx()
178	// if err != nil {
179	//         return err
180	// }
181	// tx.Put(ethTx.Hash(), ethTx.Bytes())
182	// if err := tx.Commit(); err!=nil {
183	//         return nil
184	// }
185
186	return nil
187}
188
189func (c *Coordinator) forgeConfirmationSequence() error {
190	// TODO strategy of this sequence TBD
191	// confirm eth txs and mark them as accepted sequence
192	// ethTx := ethTxStore.GetFirstPending()
193	// waitForAccepted(ethTx) // blocking call, returns once the ethTx is mined
194	// ethTxStore.MarkAccepted(ethTx)
195	return nil
196}
197
198func (c *Coordinator) handleReorg() error {
199	return nil
200}
201
202// isForgeSequence returns true if the node is the Forger in the current ethereum block
203func (c *Coordinator) isForgeSequence() bool {
204
205	return false
206}
207
208func (c *Coordinator) purgeRemoveByTimeout() error {
209
210	return nil
211}
212
213func (c *Coordinator) purgeInvalidDueToL2TxsSelection(l2Txs []common.PoolL2Tx) error {
214
215	return nil
216}
217
218func (c *Coordinator) shouldL1L2Batch() bool {
219
220	return false
221}
222
223func (c *Coordinator) prepareCallDataForge(batchInfo *BatchInfo) *common.CallDataForge {
224	return nil
225}