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.Client
 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.NewClient() // 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 poolL2Txs []*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, poolL2Txs, 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		poolL2Txs, 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 poolL2Txs 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(poolL2Txs)
128	if err != nil {
129		return err
130	}
131
132	// 3.  Save metadata from TxSelector output for BatchNum
133	batchInfo.SetTxsInfo(l1UserTxsExtra, l1OperatorTxs, poolL2Txs) // TODO feesInfo
134
135	// 4. Call BatchBuilder with TxSelector output
136	configBatch := &batchbuilder.ConfigBatch{
137		ForgerAddress: c.config.ForgerAddress,
138	}
139	l2Txs := common.PoolL2TxsToL2Txs(poolL2Txs)
140	zkInputs, err := c.batchBuilder.BuildBatch(configBatch, l1UserTxsExtra, l1OperatorTxs, l2Txs, nil) // TODO []common.TokenID --> feesInfo
141	if err != nil {
142		return err
143	}
144
145	// 5. Save metadata from BatchBuilder output for BatchNum
146	batchInfo.SetZKInputs(zkInputs)
147
148	// 6. Call an idle server proof with BatchBuilder output, save server proof info for batchNum
149	err = batchInfo.serverProof.CalculateProof(zkInputs)
150	if err != nil {
151		return err
152	}
153	c.batchQueue.Push(&batchInfo)
154
155	return nil
156}
157
158// proveSequence gets the generated zkProof & sends it to the SmartContract
159func (c *Coordinator) proveSequence() error {
160	batchInfo := c.batchQueue.Pop()
161	if batchInfo == nil {
162		// no batches in queue, return
163		return common.ErrBatchQueueEmpty
164	}
165	serverProofInfo := batchInfo.serverProof
166	proof, err := serverProofInfo.GetProof() // blocking call, until not resolved don't continue. Returns when the proof server has calculated the proof
167	if err != nil {
168		return err
169	}
170	batchInfo.SetProof(proof)
171	callData := c.prepareCallDataForge(batchInfo)
172	_, err = c.ethClient.ForgeCall(callData)
173	if err != nil {
174		return err
175	}
176	// TODO once tx data type is defined, store ethTx (returned by ForgeCall)
177	// TBD if use ethTxStore as a disk k-v database, or use a Queue
178	// tx, err := c.ethTxStore.NewTx()
179	// if err != nil {
180	//         return err
181	// }
182	// tx.Put(ethTx.Hash(), ethTx.Bytes())
183	// if err := tx.Commit(); err!=nil {
184	//         return nil
185	// }
186
187	return nil
188}
189
190func (c *Coordinator) forgeConfirmationSequence() error {
191	// TODO strategy of this sequence TBD
192	// confirm eth txs and mark them as accepted sequence
193	// ethTx := ethTxStore.GetFirstPending()
194	// waitForAccepted(ethTx) // blocking call, returns once the ethTx is mined
195	// ethTxStore.MarkAccepted(ethTx)
196	return nil
197}
198
199func (c *Coordinator) handleReorg() error {
200	return nil
201}
202
203// isForgeSequence returns true if the node is the Forger in the current ethereum block
204func (c *Coordinator) isForgeSequence() bool {
205
206	return false
207}
208
209func (c *Coordinator) purgeRemoveByTimeout() error {
210
211	return nil
212}
213
214func (c *Coordinator) purgeInvalidDueToL2TxsSelection(l2Txs []*common.PoolL2Tx) error {
215
216	return nil
217}
218
219func (c *Coordinator) shouldL1L2Batch() bool {
220
221	return false
222}
223
224func (c *Coordinator) prepareCallDataForge(batchInfo *BatchInfo) *common.CallDataForge {
225	return nil
226}