diff --git a/common/l1tx.go b/common/l1tx.go index 8351476..e4018cf 100644 --- a/common/l1tx.go +++ b/common/l1tx.go @@ -50,74 +50,88 @@ type L1Tx struct { // NewL1Tx returns the given L1Tx with the TxId & Type parameters calculated // from the L1Tx values -func NewL1Tx(l1Tx *L1Tx) (*L1Tx, error) { - // calculate TxType - var txType TxType - if l1Tx.FromIdx == 0 { - if l1Tx.ToIdx == Idx(0) { - txType = TxTypeCreateAccountDeposit - } else if l1Tx.ToIdx >= IdxUserThreshold { - txType = TxTypeCreateAccountDepositTransfer +func NewL1Tx(tx *L1Tx) (*L1Tx, error) { + txTypeOld := tx.Type + if err := tx.SetType(); err != nil { + return nil, err + } + // If original Type doesn't match the correct one, return error + if txTypeOld != "" && txTypeOld != tx.Type { + return nil, tracerr.Wrap(fmt.Errorf("L1Tx.Type: %s, should be: %s", + tx.Type, txTypeOld)) + } + + txIDOld := tx.TxID + if err := tx.SetID(); err != nil { + return nil, err + } + // If original TxID doesn't match the correct one, return error + if txIDOld != (TxID{}) && txIDOld != tx.TxID { + return tx, tracerr.Wrap(fmt.Errorf("L1Tx.TxID: %s, should be: %s", + tx.TxID.String(), txIDOld.String())) + } + + return tx, nil +} + +// SetType sets the type of the transaction +func (tx *L1Tx) SetType() error { + if tx.FromIdx == 0 { + if tx.ToIdx == Idx(0) { + tx.Type = TxTypeCreateAccountDeposit + } else if tx.ToIdx >= IdxUserThreshold { + tx.Type = TxTypeCreateAccountDepositTransfer } else { - return l1Tx, tracerr.Wrap(fmt.Errorf("Can not determine type of L1Tx, invalid ToIdx value: %d", l1Tx.ToIdx)) + return tracerr.Wrap(fmt.Errorf( + "Can not determine type of L1Tx, invalid ToIdx value: %d", tx.ToIdx)) } - } else if l1Tx.FromIdx >= IdxUserThreshold { - if l1Tx.ToIdx == Idx(0) { - txType = TxTypeDeposit - } else if l1Tx.ToIdx == Idx(1) { - txType = TxTypeForceExit - } else if l1Tx.ToIdx >= IdxUserThreshold { - if l1Tx.DepositAmount.Int64() == int64(0) { - txType = TxTypeForceTransfer + } else if tx.FromIdx >= IdxUserThreshold { + if tx.ToIdx == Idx(0) { + tx.Type = TxTypeDeposit + } else if tx.ToIdx == Idx(1) { + tx.Type = TxTypeForceExit + } else if tx.ToIdx >= IdxUserThreshold { + if tx.DepositAmount.Int64() == int64(0) { + tx.Type = TxTypeForceTransfer } else { - txType = TxTypeDepositTransfer + tx.Type = TxTypeDepositTransfer } } else { - return l1Tx, tracerr.Wrap(fmt.Errorf("Can not determine type of L1Tx, invalid ToIdx value: %d", l1Tx.ToIdx)) + return tracerr.Wrap(fmt.Errorf( + "Can not determine type of L1Tx, invalid ToIdx value: %d", tx.ToIdx)) } } else { - return l1Tx, tracerr.Wrap(fmt.Errorf("Can not determine type of L1Tx, invalid FromIdx value: %d", l1Tx.FromIdx)) - } - - if l1Tx.Type != "" && l1Tx.Type != txType { - return l1Tx, tracerr.Wrap(fmt.Errorf("L1Tx.Type: %s, should be: %s", l1Tx.Type, txType)) - } - l1Tx.Type = txType - - txID, err := l1Tx.CalcTxID() - if err != nil { - return nil, tracerr.Wrap(err) + return tracerr.Wrap(fmt.Errorf( + "Can not determine type of L1Tx, invalid FromIdx value: %d", tx.FromIdx)) } - l1Tx.TxID = *txID - - return l1Tx, nil + return nil } -// CalcTxID calculates the TxId of the L1Tx -func (tx *L1Tx) CalcTxID() (*TxID, error) { - var txID TxID +// SetID sets the ID of the transaction. For L1UserTx uses (ToForgeL1TxsNum, +// Position), for L1CoordinatorTx uses (BatchNum, Position). +func (tx *L1Tx) SetID() error { if tx.UserOrigin { if tx.ToForgeL1TxsNum == nil { - return nil, tracerr.Wrap(fmt.Errorf("L1Tx.UserOrigin == true && L1Tx.ToForgeL1TxsNum == nil")) + return tracerr.Wrap(fmt.Errorf("L1Tx.UserOrigin == true && L1Tx.ToForgeL1TxsNum == nil")) } - txID[0] = TxIDPrefixL1UserTx + tx.TxID[0] = TxIDPrefixL1UserTx var toForgeL1TxsNumBytes [8]byte binary.BigEndian.PutUint64(toForgeL1TxsNumBytes[:], uint64(*tx.ToForgeL1TxsNum)) - copy(txID[1:9], toForgeL1TxsNumBytes[:]) + copy(tx.TxID[1:9], toForgeL1TxsNumBytes[:]) } else { if tx.BatchNum == nil { - return nil, tracerr.Wrap(fmt.Errorf("L1Tx.UserOrigin == false && L1Tx.BatchNum == nil")) + return tracerr.Wrap(fmt.Errorf("L1Tx.UserOrigin == false && L1Tx.BatchNum == nil")) } - txID[0] = TxIDPrefixL1CoordTx + tx.TxID[0] = TxIDPrefixL1CoordTx var batchNumBytes [8]byte binary.BigEndian.PutUint64(batchNumBytes[:], uint64(*tx.BatchNum)) - copy(txID[1:9], batchNumBytes[:]) + copy(tx.TxID[1:9], batchNumBytes[:]) } var positionBytes [2]byte binary.BigEndian.PutUint16(positionBytes[:], uint16(tx.Position)) - copy(txID[9:11], positionBytes[:]) + copy(tx.TxID[9:11], positionBytes[:]) - return &txID, nil + return nil } // Tx returns a *Tx from the L1Tx diff --git a/common/l2tx.go b/common/l2tx.go index da78bd0..8a197ad 100644 --- a/common/l2tx.go +++ b/common/l2tx.go @@ -24,38 +24,57 @@ type L2Tx struct { // NewL2Tx returns the given L2Tx with the TxId & Type parameters calculated // from the L2Tx values -func NewL2Tx(l2Tx *L2Tx) (*L2Tx, error) { - // calculate TxType - var txType TxType - if l2Tx.ToIdx == Idx(1) { - txType = TxTypeExit - } else if l2Tx.ToIdx >= IdxUserThreshold { - txType = TxTypeTransfer - } else { - return l2Tx, tracerr.Wrap(fmt.Errorf("Can not determine type of L2Tx, invalid ToIdx value: %d", l2Tx.ToIdx)) +func NewL2Tx(tx *L2Tx) (*L2Tx, error) { + txTypeOld := tx.Type + if err := tx.SetType(); err != nil { + return nil, err + } + // If original Type doesn't match the correct one, return error + if txTypeOld != "" && txTypeOld != tx.Type { + return nil, tracerr.Wrap(fmt.Errorf("L2Tx.Type: %s, should be: %s", + tx.Type, txTypeOld)) + } + + txIDOld := tx.TxID + if err := tx.SetID(); err != nil { + return nil, err + } + // If original TxID doesn't match the correct one, return error + if txIDOld != (TxID{}) && txIDOld != tx.TxID { + return tx, tracerr.Wrap(fmt.Errorf("L2Tx.TxID: %s, should be: %s", + tx.TxID.String(), txIDOld.String())) } - // if TxType!=l2Tx.TxType return error - if l2Tx.Type != "" && l2Tx.Type != txType { - return l2Tx, tracerr.Wrap(fmt.Errorf("L2Tx.Type: %s, should be: %s", l2Tx.Type, txType)) + return tx, nil +} + +// SetType sets the type of the transaction. Uses (FromIdx, Nonce). +func (tx *L2Tx) SetType() error { + if tx.ToIdx == Idx(1) { + tx.Type = TxTypeExit + } else if tx.ToIdx >= IdxUserThreshold { + tx.Type = TxTypeTransfer + } else { + return tracerr.Wrap(fmt.Errorf( + "cannot determine type of L2Tx, invalid ToIdx value: %d", tx.ToIdx)) } - l2Tx.Type = txType + return nil +} - var txid [TxIDLen]byte - txid[0] = TxIDPrefixL2Tx - fromIdxBytes, err := l2Tx.FromIdx.Bytes() +// SetID sets the ID of the transaction +func (tx *L2Tx) SetID() error { + tx.TxID[0] = TxIDPrefixL2Tx + fromIdxBytes, err := tx.FromIdx.Bytes() if err != nil { - return l2Tx, tracerr.Wrap(err) + return tracerr.Wrap(err) } - copy(txid[1:7], fromIdxBytes[:]) - nonceBytes, err := l2Tx.Nonce.Bytes() + copy(tx.TxID[1:7], fromIdxBytes[:]) + nonceBytes, err := tx.Nonce.Bytes() if err != nil { - return l2Tx, tracerr.Wrap(err) + return tracerr.Wrap(err) } - copy(txid[7:12], nonceBytes[:]) - l2Tx.TxID = TxID(txid) - - return l2Tx, nil + copy(tx.TxID[7:12], nonceBytes[:]) + return nil } // Tx returns a *Tx from the L2Tx diff --git a/common/pooll2tx.go b/common/pooll2tx.go index d52c85e..b256768 100644 --- a/common/pooll2tx.go +++ b/common/pooll2tx.go @@ -50,49 +50,62 @@ type PoolL2Tx struct { // NewPoolL2Tx returns the given L2Tx with the TxId & Type parameters calculated // from the L2Tx values -func NewPoolL2Tx(poolL2Tx *PoolL2Tx) (*PoolL2Tx, error) { - // calculate TxType - var txType TxType - if poolL2Tx.ToIdx >= IdxUserThreshold { - txType = TxTypeTransfer - } else if poolL2Tx.ToIdx == 1 { - txType = TxTypeExit - } else if poolL2Tx.ToIdx == 0 { - if poolL2Tx.ToBJJ != nil && poolL2Tx.ToEthAddr == FFAddr { - txType = TxTypeTransferToBJJ - } else if poolL2Tx.ToEthAddr != FFAddr && poolL2Tx.ToEthAddr != EmptyAddr { - txType = TxTypeTransferToEthAddr - } - } else { - return nil, tracerr.Wrap(errors.New("malformed transaction")) +func NewPoolL2Tx(tx *PoolL2Tx) (*PoolL2Tx, error) { + txTypeOld := tx.Type + if err := tx.SetType(); err != nil { + return nil, err + } + // If original Type doesn't match the correct one, return error + if txTypeOld != "" && txTypeOld != tx.Type { + return nil, tracerr.Wrap(fmt.Errorf("L2Tx.Type: %s, should be: %s", + tx.Type, txTypeOld)) } - // if TxType!=poolL2Tx.TxType return error - if poolL2Tx.Type != "" && poolL2Tx.Type != txType { - return poolL2Tx, tracerr.Wrap(fmt.Errorf("type: %s, should be: %s", poolL2Tx.Type, txType)) + txIDOld := tx.TxID + if err := tx.SetID(); err != nil { + return nil, err + } + // If original TxID doesn't match the correct one, return error + if txIDOld != (TxID{}) && txIDOld != tx.TxID { + return tx, tracerr.Wrap(fmt.Errorf("PoolL2Tx.TxID: %s, should be: %s", + tx.TxID.String(), txIDOld.String())) } - poolL2Tx.Type = txType - var txid [TxIDLen]byte - txid[0] = TxIDPrefixL2Tx - fromIdxBytes, err := poolL2Tx.FromIdx.Bytes() - if err != nil { - return poolL2Tx, tracerr.Wrap(err) + return tx, nil +} + +// SetType sets the type of the transaction +func (tx *PoolL2Tx) SetType() error { + if tx.ToIdx >= IdxUserThreshold { + tx.Type = TxTypeTransfer + } else if tx.ToIdx == 1 { + tx.Type = TxTypeExit + } else if tx.ToIdx == 0 { + if tx.ToBJJ != nil && tx.ToEthAddr == FFAddr { + tx.Type = TxTypeTransferToBJJ + } else if tx.ToEthAddr != FFAddr && tx.ToEthAddr != EmptyAddr { + tx.Type = TxTypeTransferToEthAddr + } + } else { + return tracerr.Wrap(errors.New("malformed transaction")) } - copy(txid[1:7], fromIdxBytes[:]) - nonceBytes, err := poolL2Tx.Nonce.Bytes() + return nil +} + +// SetID sets the ID of the transaction. Uses (FromIdx, Nonce). +func (tx *PoolL2Tx) SetID() error { + tx.TxID[0] = TxIDPrefixL2Tx + fromIdxBytes, err := tx.FromIdx.Bytes() if err != nil { - return poolL2Tx, tracerr.Wrap(err) + return tracerr.Wrap(err) } - copy(txid[7:12], nonceBytes[:]) - txID := TxID(txid) - - // if TxID!=poolL2Tx.TxID return error - if poolL2Tx.TxID != (TxID{}) && poolL2Tx.TxID != txID { - return poolL2Tx, tracerr.Wrap(fmt.Errorf("id: %s, should be: %s", poolL2Tx.TxID.String(), txID.String())) + copy(tx.TxID[1:7], fromIdxBytes[:]) + nonceBytes, err := tx.Nonce.Bytes() + if err != nil { + return tracerr.Wrap(err) } - poolL2Tx.TxID = txID - return poolL2Tx, nil + copy(tx.TxID[7:12], nonceBytes[:]) + return nil } // TxCompressedData spec: @@ -305,11 +318,11 @@ func (tx PoolL2Tx) Tx() Tx { // PoolL2TxsToL2Txs returns an array of []L2Tx from an array of []PoolL2Tx func PoolL2TxsToL2Txs(txs []PoolL2Tx) ([]L2Tx, error) { - var r []L2Tx - for _, poolTx := range txs { - r = append(r, poolTx.L2Tx()) + l2Txs := make([]L2Tx, len(txs)) + for i, poolTx := range txs { + l2Txs[i] = poolTx.L2Tx() } - return r, nil + return l2Txs, nil } // PoolL2TxState is a struct that represents the status of a L2 transaction diff --git a/db/historydb/historydb_test.go b/db/historydb/historydb_test.go index e0d1552..0546f43 100644 --- a/db/historydb/historydb_test.go +++ b/db/historydb/historydb_test.go @@ -144,9 +144,9 @@ func TestBatches(t *testing.T) { CoordUser: "A", } blocks, err := tc.GenerateBlocks(set) - require.Nil(t, err) + require.NoError(t, err) err = tc.FillBlocksExtra(blocks, &tilCfgExtra) - assert.Nil(t, err) + require.NoError(t, err) // Insert to DB batches := []common.Batch{} tokensValue := make(map[common.TokenID]float64) @@ -365,9 +365,9 @@ func TestTxs(t *testing.T) { CoordUser: "A", } blocks, err := tc.GenerateBlocks(set) - require.Nil(t, err) + require.NoError(t, err) err = tc.FillBlocksExtra(blocks, &tilCfgExtra) - assert.Nil(t, err) + require.NoError(t, err) // Sanity check require.Equal(t, 7, len(blocks)) @@ -617,7 +617,7 @@ func TestGetUnforgedL1UserTxs(t *testing.T) { ` tc := til.NewContext(128) blocks, err := tc.GenerateBlocks(set) - require.Nil(t, err) + require.NoError(t, err) // Sanity check require.Equal(t, 1, len(blocks)) require.Equal(t, 5, len(blocks[0].Rollup.L1UserTxs)) @@ -626,17 +626,17 @@ func TestGetUnforgedL1UserTxs(t *testing.T) { for i := range blocks { err = historyDB.AddBlockSCData(&blocks[i]) - require.Nil(t, err) + require.NoError(t, err) } l1UserTxs, err := historyDB.GetUnforgedL1UserTxs(toForgeL1TxsNum) - require.Nil(t, err) + require.NoError(t, err) assert.Equal(t, 5, len(l1UserTxs)) assert.Equal(t, blocks[0].Rollup.L1UserTxs, l1UserTxs) // No l1UserTxs for this toForgeL1TxsNum l1UserTxs, err = historyDB.GetUnforgedL1UserTxs(2) - require.Nil(t, err) + require.NoError(t, err) assert.Equal(t, 0, len(l1UserTxs)) } @@ -685,9 +685,9 @@ func TestSetInitialSCVars(t *testing.T) { assert.Equal(t, sql.ErrNoRows, tracerr.Unwrap(err)) rollup, auction, wDelayer := exampleInitSCVars() err = historyDB.SetInitialSCVars(rollup, auction, wDelayer) - require.Nil(t, err) + require.NoError(t, err) dbRollup, dbAuction, dbWDelayer, err := historyDB.GetSCVars() - assert.Nil(t, err) + require.NoError(t, err) require.Equal(t, rollup, dbRollup) require.Equal(t, auction, dbAuction) require.Equal(t, wDelayer, dbWDelayer) @@ -718,16 +718,16 @@ func TestSetL1UserTxEffectiveAmounts(t *testing.T) { CoordUser: "A", } blocks, err := tc.GenerateBlocks(set) - require.Nil(t, err) + require.NoError(t, err) err = tc.FillBlocksExtra(blocks, &tilCfgExtra) - assert.Nil(t, err) + require.NoError(t, err) err = tc.FillBlocksForgedL1UserTxs(blocks) - require.Nil(t, err) + require.NoError(t, err) // Add only first block so that the L1UserTxs are not marked as forged for i := range blocks[:1] { err = historyDB.AddBlockSCData(&blocks[i]) - require.Nil(t, err) + require.NoError(t, err) } // Add second batch to trigger the update of the batch_num, // while avoiding the implicit call of setL1UserTxEffectiveAmounts @@ -735,7 +735,7 @@ func TestSetL1UserTxEffectiveAmounts(t *testing.T) { assert.NoError(t, err) err = historyDB.addBatch(historyDB.db, &blocks[1].Rollup.Batches[0].Batch) assert.NoError(t, err) - require.Nil(t, err) + require.NoError(t, err) // Set the Effective{Amount,DepositAmount} of the L1UserTxs that are forged in the second block l1Txs := blocks[1].Rollup.Batches[0].L1UserTxs @@ -805,14 +805,14 @@ func TestUpdateExitTree(t *testing.T) { CoordUser: "A", } blocks, err := tc.GenerateBlocks(set) - require.Nil(t, err) + require.NoError(t, err) err = tc.FillBlocksExtra(blocks, &tilCfgExtra) - assert.Nil(t, err) + require.NoError(t, err) // Add all blocks except for the last two for i := range blocks[:len(blocks)-2] { err = historyDB.AddBlockSCData(&blocks[i]) - require.Nil(t, err) + require.NoError(t, err) } // Add withdraws to the second-to-last block, and insert block into the DB @@ -832,15 +832,15 @@ func TestUpdateExitTree(t *testing.T) { Owner: tc.UsersByIdx[259].Addr, Token: tokenAddr}, ) err = historyDB.addBlock(historyDB.db, &block.Block) - require.Nil(t, err) + require.NoError(t, err) err = historyDB.updateExitTree(historyDB.db, block.Block.Num, block.Rollup.Withdrawals, block.WDelayer.Withdrawals) - require.Nil(t, err) + require.NoError(t, err) // Check that exits in DB match with the expected values dbExits, err := historyDB.GetAllExits() - require.Nil(t, err) + require.NoError(t, err) assert.Equal(t, 4, len(dbExits)) dbExitsByIdx := make(map[common.Idx]common.ExitInfo) for _, dbExit := range dbExits { @@ -865,15 +865,15 @@ func TestUpdateExitTree(t *testing.T) { Amount: big.NewInt(80), }) err = historyDB.addBlock(historyDB.db, &block.Block) - require.Nil(t, err) + require.NoError(t, err) err = historyDB.updateExitTree(historyDB.db, block.Block.Num, block.Rollup.Withdrawals, block.WDelayer.Withdrawals) - require.Nil(t, err) + require.NoError(t, err) // Check that delayed withdrawn has been set dbExits, err = historyDB.GetAllExits() - require.Nil(t, err) + require.NoError(t, err) for _, dbExit := range dbExits { dbExitsByIdx[dbExit.AccountIdx] = dbExit } @@ -885,16 +885,16 @@ func TestGetBestBidCoordinator(t *testing.T) { rollup, auction, wDelayer := exampleInitSCVars() err := historyDB.SetInitialSCVars(rollup, auction, wDelayer) - require.Nil(t, err) + require.NoError(t, err) tc := til.NewContext(common.RollupConstMaxL1UserTx) blocks, err := tc.GenerateBlocks(` Type: Blockchain > block // blockNum=2 `) - require.Nil(t, err) + require.NoError(t, err) err = historyDB.AddBlockSCData(&blocks[0]) - require.Nil(t, err) + require.NoError(t, err) coords := []common.Coordinator{ { @@ -911,7 +911,7 @@ func TestGetBestBidCoordinator(t *testing.T) { }, } err = historyDB.addCoordinators(historyDB.db, coords) - require.Nil(t, err) + require.NoError(t, err) err = historyDB.addBids(historyDB.db, []common.Bid{ { SlotNum: 10, @@ -926,10 +926,10 @@ func TestGetBestBidCoordinator(t *testing.T) { Bidder: coords[1].Bidder, }, }) - require.Nil(t, err) + require.NoError(t, err) forger10, err := historyDB.GetBestBidCoordinator(10) - require.Nil(t, err) + require.NoError(t, err) require.Equal(t, coords[1].Forger, forger10.Forger) require.Equal(t, coords[1].Bidder, forger10.Bidder) require.Equal(t, coords[1].URL, forger10.URL) diff --git a/synchronizer/synchronizer.go b/synchronizer/synchronizer.go index 1f4d707..ae77941 100644 --- a/synchronizer/synchronizer.go +++ b/synchronizer/synchronizer.go @@ -753,13 +753,11 @@ func (s *Synchronizer) rollupSync(ethBlock *common.Block) (*common.RollupData, e // L1CoordinatorTxs, PoolL2Txs) into stateDB so that they are // processed. - // Add TxID, TxType, Position, BlockNum and BatchNum to L2 txs + // Set TxType to the forged L2Txs for i := range forgeBatchArgs.L2TxsData { - nTx, err := common.NewL2Tx(&forgeBatchArgs.L2TxsData[i]) - if err != nil { + if err := forgeBatchArgs.L2TxsData[i].SetType(); err != nil { return nil, tracerr.Wrap(err) } - forgeBatchArgs.L2TxsData[i] = *nTx } // Transform L2 txs to PoolL2Txs @@ -780,19 +778,22 @@ func (s *Synchronizer) rollupSync(ethBlock *common.Block) (*common.RollupData, e } // Transform processed PoolL2 txs to L2 and store in BatchData - if poolL2Txs != nil { - l2Txs, err := common.PoolL2TxsToL2Txs(poolL2Txs) // NOTE: This is a big uggly, find a better way - if err != nil { - return nil, tracerr.Wrap(err) - } - for i := range l2Txs { - l2Txs[i].Position = position - l2Txs[i].EthBlockNum = blockNum - l2Txs[i].BatchNum = batchNum - position++ + l2Txs, err := common.PoolL2TxsToL2Txs(poolL2Txs) // NOTE: This is a big uggly, find a better way + if err != nil { + return nil, tracerr.Wrap(err) + } + + // Set TxID, BlockNum, BatchNum and Position to the forged L2Txs + for i := range l2Txs { + if err := l2Txs[i].SetID(); err != nil { + return nil, err } - batchData.L2Txs = l2Txs + l2Txs[i].EthBlockNum = blockNum + l2Txs[i].BatchNum = batchNum + l2Txs[i].Position = position + position++ } + batchData.L2Txs = l2Txs // Set the BatchNum in the forged L1UserTxs for i := range l1UserTxs { diff --git a/test/til/txs.go b/test/til/txs.go index b8ae1ec..889e5f6 100644 --- a/test/til/txs.go +++ b/test/til/txs.go @@ -882,6 +882,9 @@ func (tc *Context) FillBlocksExtra(blocks []common.BlockData, cfg *ConfigExtra) position++ tc.extra.nonces[tx.FromIdx]++ tx.Nonce = tc.extra.nonces[tx.FromIdx] + if err := tx.SetID(); err != nil { + return err + } nTx, err := common.NewL2Tx(tx) if err != nil { return tracerr.Wrap(err)