From 80cbac24f98b66bc418d0fd39a92937239be4c50 Mon Sep 17 00:00:00 2001 From: arnaucube Date: Tue, 1 Dec 2020 22:15:19 +0100 Subject: [PATCH] StateDB ZKInputs generation compatible with circom - Add SignatureConstant to L1Tx.TxCompressedData - ZKInputs generation works initial version working and compatible with circom Hermez circuit - Lots of small updates for circuits compatibility - Update version (with new changes) of `go-iden3-crypto` & `go-merkletree` --- common/l1tx.go | 7 +- common/l1tx_test.go | 4 +- common/pooll2tx.go | 10 +-- common/pooll2tx_test.go | 22 +++--- common/tx.go | 7 ++ common/tx_test.go | 10 +++ common/zk.go | 16 +++-- db/statedb/txprocessors.go | 124 ++++++++++++++++++++------------ db/statedb/txprocessors_test.go | 48 +++++++++---- go.mod | 6 +- go.sum | 4 ++ test/til/lang.go | 10 +-- test/til/txs.go | 22 +++--- 13 files changed, 186 insertions(+), 104 deletions(-) diff --git a/common/l1tx.go b/common/l1tx.go index 7d542c8..278faef 100644 --- a/common/l1tx.go +++ b/common/l1tx.go @@ -167,8 +167,9 @@ func (tx L1Tx) TxCompressedData() (*big.Int, error) { if err != nil { return nil, tracerr.Wrap(err) } + var b [31]byte - // b[0:7] empty: no fee neither nonce + // b[0:7] empty: no ToBJJSign, no fee, no nonce copy(b[7:11], tx.TokenID.Bytes()) copy(b[11:13], amountFloat16.Bytes()) toIdxBytes, err := tx.ToIdx.Bytes() @@ -181,8 +182,8 @@ func (tx L1Tx) TxCompressedData() (*big.Int, error) { return nil, tracerr.Wrap(err) } copy(b[19:25], fromIdxBytes[:]) - copy(b[25:27], []byte{0, 1}) // TODO this will be generated by the ChainID config parameter - // b[27:] empty: no signature + copy(b[25:27], []byte{0, 0}) // TODO this will be generated by the ChainID config parameter + copy(b[27:31], SignatureConstantBytes[:]) bi := new(big.Int).SetBytes(b[:]) return bi, nil diff --git a/common/l1tx_test.go b/common/l1tx_test.go index ead8c7e..31d5f2e 100644 --- a/common/l1tx_test.go +++ b/common/l1tx_test.go @@ -60,9 +60,9 @@ func TestL1TxCompressedData(t *testing.T) { assert.Nil(t, err) // test vector value generated from javascript implementation - expectedStr := "7307597389635308713748674793997299267460566876160" + expectedStr := "7307597389635308713748674793997299267459594577423" assert.Equal(t, expectedStr, txCompressedData.String()) - assert.Equal(t, "050004000000000003000000000002000100000000", hex.EncodeToString(txCompressedData.Bytes())) + assert.Equal(t, "0500040000000000030000000000020000c60be60f", hex.EncodeToString(txCompressedData.Bytes())) } func TestBytesDataAvailability(t *testing.T) { diff --git a/common/pooll2tx.go b/common/pooll2tx.go index 20de40e..5fc9203 100644 --- a/common/pooll2tx.go +++ b/common/pooll2tx.go @@ -107,12 +107,6 @@ func NewPoolL2Tx(poolL2Tx *PoolL2Tx) (*PoolL2Tx, error) { // [ 32 bits ] signatureConstant // 4 bytes // Total bits compressed data: 241 bits // 31 bytes in *big.Int representation func (tx *PoolL2Tx) TxCompressedData() (*big.Int, error) { - // sigconstant - sc, ok := new(big.Int).SetString("3322668559", 10) - if !ok { - return nil, tracerr.Wrap(fmt.Errorf("error parsing SignatureConstant")) - } - amountFloat16, err := NewFloat16(tx.Amount) if err != nil { return nil, tracerr.Wrap(err) @@ -141,8 +135,8 @@ func (tx *PoolL2Tx) TxCompressedData() (*big.Int, error) { return nil, tracerr.Wrap(err) } copy(b[19:25], fromIdxBytes[:]) - copy(b[25:27], []byte{0, 1}) // TODO this will be generated by the ChainID config parameter - copy(b[27:31], sc.Bytes()) + copy(b[25:27], []byte{0, 0}) // TODO this will be generated by the ChainID config parameter + copy(b[27:31], SignatureConstantBytes[:]) bi := new(big.Int).SetBytes(b[:]) return bi, nil diff --git a/common/pooll2tx_test.go b/common/pooll2tx_test.go index 0d0a3d1..a443cc0 100644 --- a/common/pooll2tx_test.go +++ b/common/pooll2tx_test.go @@ -38,9 +38,9 @@ func TestTxCompressedData(t *testing.T) { txCompressedData, err := tx.TxCompressedData() assert.Nil(t, err) // test vector value generated from javascript implementation - expectedStr := "1766847064778421992193717128424891165872736891548909569553540449389241871" + expectedStr := "1766847064778421992193717128424891165872736891548909569553540445094274575" assert.Equal(t, expectedStr, txCompressedData.String()) - assert.Equal(t, "010000000000060000000500040000000000030000000000020001c60be60f", hex.EncodeToString(txCompressedData.Bytes())) + assert.Equal(t, "010000000000060000000500040000000000030000000000020000c60be60f", hex.EncodeToString(txCompressedData.Bytes())) tx = PoolL2Tx{ RqFromIdx: 7, RqToIdx: 8, @@ -112,18 +112,16 @@ func TestHashToSign(t *testing.T) { _, err := hex.Decode(sk[:], []byte("0001020304050607080900010203040506070809000102030405060708090001")) assert.Nil(t, err) tx := PoolL2Tx{ - FromIdx: 2, - ToIdx: 3, - Amount: big.NewInt(4), - TokenID: 5, - Nonce: 6, - ToBJJ: sk.Public(), - RqToEthAddr: ethCommon.HexToAddress("0xc58d29fA6e86E4FAe04DDcEd660d45BCf3Cb2370"), - RqToBJJ: sk.Public(), + FromIdx: 2, + ToIdx: 3, + Amount: big.NewInt(4), + TokenID: 5, + Nonce: 6, + ToEthAddr: ethCommon.HexToAddress("0xc58d29fA6e86E4FAe04DDcEd660d45BCf3Cb2370"), } toSign, err := tx.HashToSign() assert.Nil(t, err) - assert.Equal(t, "13412877307445712067533842795279849753265998687662992184595695642580679868064", toSign.String()) + assert.Equal(t, "1469900657138253851938022936440971384682713995864967090251961124784132925291", toSign.String()) } func TestVerifyTxSignature(t *testing.T) { @@ -142,7 +140,7 @@ func TestVerifyTxSignature(t *testing.T) { } toSign, err := tx.HashToSign() assert.Nil(t, err) - assert.Equal(t, "13412877307445712067533842795279849753265998687662992184595695642580679868064", toSign.String()) + assert.Equal(t, "18645218094210271622244722988708640202588315450486586312909439859037906375295", toSign.String()) sig := sk.SignPoseidon(toSign) tx.Signature = sig.Compress() diff --git a/common/tx.go b/common/tx.go index 847f49d..ca44f4a 100644 --- a/common/tx.go +++ b/common/tx.go @@ -34,6 +34,13 @@ const ( TxIDLen = 12 ) +var ( + // SignatureConstantBytes contains the SignatureConstant in byte array + // format, which is equivalent to 3322668559 as uint32 in byte array in + // big endian representation. + SignatureConstantBytes = []byte{198, 11, 230, 15} +) + // TxID is the identifier of a Hermez network transaction type TxID [TxIDLen]byte diff --git a/common/tx_test.go b/common/tx_test.go index ff45af8..51e2cb2 100644 --- a/common/tx_test.go +++ b/common/tx_test.go @@ -3,11 +3,21 @@ package common import ( "database/sql" "database/sql/driver" + "encoding/binary" + "encoding/hex" "testing" "github.com/stretchr/testify/assert" ) +func TestSignatureConstant(t *testing.T) { + signatureConstant := uint32(3322668559) + var signatureConstantBytes [4]byte + binary.BigEndian.PutUint32(signatureConstantBytes[:], signatureConstant) + assert.Equal(t, SignatureConstantBytes, signatureConstantBytes[:]) + assert.Equal(t, "c60be60f", hex.EncodeToString(SignatureConstantBytes)) +} + func TestTxIDScannerValue(t *testing.T) { txid0 := &TxID{} txid1 := &TxID{} diff --git a/common/zk.go b/common/zk.go index 3d9436a..49cb239 100644 --- a/common/zk.go +++ b/common/zk.go @@ -58,14 +58,16 @@ type ZKInputs struct { OldLastIdx *big.Int `json:"oldLastIdx"` // uint64 (max nLevels bits) // OldStateRoot is the current state merkle tree root OldStateRoot *big.Int `json:"oldStateRoot"` // Hash - // GlobalChainID is the blockchain ID (0 for Ethereum mainnet). This value can be get from the smart contract. + // GlobalChainID is the blockchain ID (0 for Ethereum mainnet). This + // value can be get from the smart contract. GlobalChainID *big.Int `json:"globalChainID"` // uint16 - // FeeIdxs is an array of merkle tree indexes where the coordinator will receive the accumulated fees + // FeeIdxs is an array of merkle tree indexes where the coordinator + // will receive the accumulated fees FeeIdxs []*big.Int `json:"feeIdxs"` // uint64 (max nLevels bits), len: [maxFeeIdxs] // accumulate fees // FeePlanTokens contains all the tokenIDs for which the fees are being accumulated - FeePlanTokens []*big.Int `json:"feePlanTokens"` // uint32 (max 32 bits), len: [maxFeeIdxs] + FeePlanTokens []*big.Int `json:"feePlanTokens"` // uint32 (max nLevels bits), len: [maxFeeIdxs] // // Txs (L1&L2) @@ -87,7 +89,9 @@ type ZKInputs struct { // ToIdx ToIdx []*big.Int `json:"toIdx"` // uint64 (max nLevels bits), len: [nTx] - // AuxToIdx is the Idx of the Tx that has 'toIdx==0', is the coordinator who will find which Idx corresponds to the 'toBJJAy' or 'toEthAddr' + // AuxToIdx is the Idx of the Tx that has 'toIdx==0', is the + // coordinator who will find which Idx corresponds to the 'toBJJAy' or + // 'toEthAddr' AuxToIdx []*big.Int `json:"auxToIdx"` // uint64 (max nLevels bits), len: [nTx] // ToBJJAy ToBJJAy []*big.Int `json:"toBjjAy"` // big.Int, len: [nTx] @@ -136,7 +140,9 @@ type ZKInputs struct { // State MerkleTree Leafs transitions // - // state 1, value of the sender (from) account leaf + // state 1, value of the sender (from) account leaf. The values at the + // moment pre-smtprocessor of the update (before updating the Sender + // leaf). TokenID1 []*big.Int `json:"tokenID1"` // uint32, len: [nTx] Nonce1 []*big.Int `json:"nonce1"` // uint64 (max 40 bits), len: [nTx] Sign1 []*big.Int `json:"sign1"` // bool, len: [nTx] diff --git a/db/statedb/txprocessors.go b/db/statedb/txprocessors.go index f4aae4e..d6555c5 100644 --- a/db/statedb/txprocessors.go +++ b/db/statedb/txprocessors.go @@ -92,10 +92,18 @@ func (s *StateDB) ProcessTxs(ptc ProcessTxsConfig, coordIdxs []common.Idx, l1use CollectedFees: nil, }, nil } + + if nTx > int(ptc.MaxTx) { + return nil, tracerr.Wrap(fmt.Errorf("L1UserTx + L1CoordinatorTx + L2Tx (%d) can not be bigger than MaxTx (%d)", nTx, ptc.MaxTx)) + } + if len(l1usertxs)+len(l1coordinatortxs) > int(ptc.MaxL1Tx) { + return nil, tracerr.Wrap(fmt.Errorf("L1UserTx + L1CoordinatorTx (%d) can not be bigger than MaxL1Tx (%d)", len(l1usertxs)+len(l1coordinatortxs), ptc.MaxTx)) + } + exits := make([]processedExit, nTx) if s.typ == TypeBatchBuilder { - s.zki = common.NewZKInputs(uint32(nTx), ptc.MaxL1Tx, ptc.MaxTx, ptc.MaxFeeTx, ptc.NLevels, s.currentBatch.BigInt()) + s.zki = common.NewZKInputs(ptc.MaxTx, ptc.MaxL1Tx, ptc.MaxTx, ptc.MaxFeeTx, ptc.NLevels, s.currentBatch.BigInt()) s.zki.OldLastIdx = s.idx.BigInt() s.zki.OldStateRoot = s.mt.Root().BigInt() } @@ -146,10 +154,8 @@ func (s *StateDB) ProcessTxs(ptc ProcessTxsConfig, coordIdxs []common.Idx, l1use } s.zki.Metadata.L1TxsDataAvailability = append(s.zki.Metadata.L1TxsDataAvailability, l1TxDataAvailability) - if s.i < nTx-1 { - s.zki.ISOutIdx[s.i] = s.idx.BigInt() - s.zki.ISStateRoot[s.i] = s.mt.Root().BigInt() - } + s.zki.ISOutIdx[s.i] = s.idx.BigInt() + s.zki.ISStateRoot[s.i] = s.mt.Root().BigInt() } if s.typ == TypeSynchronizer || s.typ == TypeBatchBuilder { if exitIdx != nil && exitTree != nil { @@ -183,10 +189,8 @@ func (s *StateDB) ProcessTxs(ptc ProcessTxsConfig, coordIdxs []common.Idx, l1use } s.zki.Metadata.L1TxsData = append(s.zki.Metadata.L1TxsData, l1TxData) - if s.i < nTx-1 { - s.zki.ISOutIdx[s.i] = s.idx.BigInt() - s.zki.ISStateRoot[s.i] = s.mt.Root().BigInt() - } + s.zki.ISOutIdx[s.i] = s.idx.BigInt() + s.zki.ISStateRoot[s.i] = s.mt.Root().BigInt() s.i++ } } @@ -260,6 +264,15 @@ func (s *StateDB) ProcessTxs(ptc ProcessTxsConfig, coordIdxs []common.Idx, l1use } if s.zki != nil { + for i := s.i - 1; i < int(ptc.MaxTx); i++ { + if i < int(ptc.MaxTx)-1 { + s.zki.ISOutIdx[i] = s.idx.BigInt() + s.zki.ISStateRoot[i] = s.mt.Root().BigInt() + } + if i >= s.i { + s.zki.TxCompressedData[i] = new(big.Int).SetBytes(common.SignatureConstantBytes) + } + } // before computing the Fees txs, set the ISInitStateRootFee s.zki.ISInitStateRootFee = s.mt.Root().BigInt() } @@ -298,6 +311,11 @@ func (s *StateDB) ProcessTxs(ptc ProcessTxsConfig, coordIdxs []common.Idx, l1use } iFee++ } + if s.zki != nil { + for i := len(s.accumulatedFees); i < int(ptc.MaxFeeTx)-1; i++ { + s.zki.ISStateRootFee[i] = s.mt.Root().BigInt() + } + } if s.typ == TypeTxSelector { return nil, nil @@ -437,7 +455,11 @@ func (s *StateDB) processL1Tx(exitTree *merkletree.MerkleTree, tx *common.L1Tx) s.zki.OnChain[s.i] = big.NewInt(1) // L1Txs - s.zki.LoadAmountF[s.i] = tx.LoadAmount + loadAmountF16, err := common.NewFloat16(tx.LoadAmount) + if err != nil { + return nil, nil, false, nil, tracerr.Wrap(err) + } + s.zki.LoadAmountF[s.i] = big.NewInt(int64(loadAmountF16)) s.zki.FromEthAddr[s.i] = common.EthAddrToBigInt(tx.FromEthAddr) if tx.FromBJJ != nil { s.zki.FromBJJCompressed[s.i] = BJJCompressedTo256BigInts(tx.FromBJJ.Compress()) @@ -587,6 +609,7 @@ func (s *StateDB) processL2Tx(coordIdxsMap map[common.TokenID]common.Idx, collec // s.zki.RqTxCompressedDataV2[s.i] = // TODO // s.zki.RqToEthAddr[s.i] = common.EthAddrToBigInt(tx.RqToEthAddr) // TODO // s.zki.RqToBJJAy[s.i] = tx.ToBJJ.Y // TODO + signature, err := tx.Signature.Decompress() if err != nil { log.Error(err) @@ -760,6 +783,18 @@ func (s *StateDB) applyTransfer(coordIdxsMap map[common.TokenID]common.Idx, log.Error(err) return tracerr.Wrap(err) } + + if s.zki != nil { + // Set the State1 before updating the Sender leaf + s.zki.TokenID1[s.i] = accSender.TokenID.BigInt() + s.zki.Nonce1[s.i] = accSender.Nonce.BigInt() + if babyjub.PointCoordSign(accSender.PublicKey.X) { + s.zki.Sign1[s.i] = big.NewInt(1) + } + s.zki.Ay1[s.i] = accSender.PublicKey.Y + s.zki.Balance1[s.i] = accSender.Balance + s.zki.EthAddr1[s.i] = common.EthAddrToBigInt(accSender.EthAddr) + } if !tx.IsL1 { // increment nonce accSender.Nonce++ @@ -772,10 +807,11 @@ func (s *StateDB) applyTransfer(coordIdxsMap map[common.TokenID]common.Idx, feeAndAmount := new(big.Int).Add(tx.Amount, fee) accSender.Balance = new(big.Int).Sub(accSender.Balance, feeAndAmount) - accCoord, err := s.GetAccount(coordIdxsMap[accSender.TokenID]) - if err != nil { - log.Debugw("No coord Idx to receive fee", "tx", tx) - } else { + if _, ok := coordIdxsMap[accSender.TokenID]; ok { + accCoord, err := s.GetAccount(coordIdxsMap[accSender.TokenID]) + if err != nil { + return tracerr.Wrap(fmt.Errorf("Can not use CoordIdx that does not exist in the tree. TokenID: %d, CoordIdx: %d", accSender.TokenID, coordIdxsMap[accSender.TokenID])) + } // accumulate the fee for the Coord account accumulated := s.accumulatedFees[accCoord.Idx] accumulated.Add(accumulated, fee) @@ -784,11 +820,23 @@ func (s *StateDB) applyTransfer(coordIdxsMap map[common.TokenID]common.Idx, collected := collectedFees[accCoord.TokenID] collected.Add(collected, fee) } + } else { + log.Debugw("No coord Idx to receive fee", "tx", tx) } } else { accSender.Balance = new(big.Int).Sub(accSender.Balance, tx.Amount) } + // update sender account in localStateDB + pSender, err := s.UpdateAccount(tx.FromIdx, accSender) + if err != nil { + log.Error(err) + return tracerr.Wrap(err) + } + if s.zki != nil { + s.zki.Siblings1[s.i] = siblingsToZKInputFormat(pSender.Siblings) + } + var accReceiver *common.Account if tx.FromIdx == auxToIdx { // if Sender is the Receiver, reuse 'accSender' pointer, @@ -802,42 +850,27 @@ func (s *StateDB) applyTransfer(coordIdxsMap map[common.TokenID]common.Idx, return tracerr.Wrap(err) } } - - // add amount-feeAmount to the receiver - accReceiver.Balance = new(big.Int).Add(accReceiver.Balance, tx.Amount) - - // update sender account in localStateDB - pSender, err := s.UpdateAccount(tx.FromIdx, accSender) - if err != nil { - log.Error(err) - return tracerr.Wrap(err) - } if s.zki != nil { - s.zki.TokenID1[s.i] = accSender.TokenID.BigInt() - s.zki.Nonce1[s.i] = accSender.Nonce.BigInt() - if babyjub.PointCoordSign(accSender.PublicKey.X) { - s.zki.Sign1[s.i] = big.NewInt(1) + // Set the State2 before updating the Receiver leaf + s.zki.TokenID2[s.i] = accReceiver.TokenID.BigInt() + s.zki.Nonce2[s.i] = accReceiver.Nonce.BigInt() + if babyjub.PointCoordSign(accReceiver.PublicKey.X) { + s.zki.Sign2[s.i] = big.NewInt(1) } - s.zki.Ay1[s.i] = accSender.PublicKey.Y - s.zki.Balance1[s.i] = accSender.Balance - s.zki.EthAddr1[s.i] = common.EthAddrToBigInt(accSender.EthAddr) - s.zki.Siblings1[s.i] = siblingsToZKInputFormat(pSender.Siblings) + s.zki.Ay2[s.i] = accReceiver.PublicKey.Y + s.zki.Balance2[s.i] = accReceiver.Balance + s.zki.EthAddr2[s.i] = common.EthAddrToBigInt(accReceiver.EthAddr) } + // add amount-feeAmount to the receiver + accReceiver.Balance = new(big.Int).Add(accReceiver.Balance, tx.Amount) + // update receiver account in localStateDB pReceiver, err := s.UpdateAccount(auxToIdx, accReceiver) if err != nil { return tracerr.Wrap(err) } if s.zki != nil { - s.zki.TokenID2[s.i] = accReceiver.TokenID.BigInt() - s.zki.Nonce2[s.i] = accReceiver.Nonce.BigInt() - if babyjub.PointCoordSign(accReceiver.PublicKey.X) { - s.zki.Sign2[s.i] = big.NewInt(1) - } - s.zki.Ay2[s.i] = accReceiver.PublicKey.Y - s.zki.Balance2[s.i] = accReceiver.Balance - s.zki.EthAddr2[s.i] = common.EthAddrToBigInt(accReceiver.EthAddr) s.zki.Siblings2[s.i] = siblingsToZKInputFormat(pReceiver.Siblings) } @@ -938,10 +971,11 @@ func (s *StateDB) applyExit(coordIdxsMap map[common.TokenID]common.Idx, feeAndAmount := new(big.Int).Add(tx.Amount, fee) acc.Balance = new(big.Int).Sub(acc.Balance, feeAndAmount) - accCoord, err := s.GetAccount(coordIdxsMap[acc.TokenID]) - if err != nil { - log.Debugw("No coord Idx to receive fee", "tx", tx) - } else { + if _, ok := coordIdxsMap[acc.TokenID]; ok { + accCoord, err := s.GetAccount(coordIdxsMap[acc.TokenID]) + if err != nil { + return nil, false, tracerr.Wrap(fmt.Errorf("Can not use CoordIdx that does not exist in the tree. TokenID: %d, CoordIdx: %d", acc.TokenID, coordIdxsMap[acc.TokenID])) + } // accumulate the fee for the Coord account accumulated := s.accumulatedFees[accCoord.Idx] accumulated.Add(accumulated, fee) @@ -950,6 +984,8 @@ func (s *StateDB) applyExit(coordIdxsMap map[common.TokenID]common.Idx, collected := collectedFees[accCoord.TokenID] collected.Add(collected, fee) } + } else { + log.Debugw("No coord Idx to receive fee", "tx", tx) } } else { acc.Balance = new(big.Int).Sub(acc.Balance, tx.Amount) diff --git a/db/statedb/txprocessors_test.go b/db/statedb/txprocessors_test.go index 63f5ae8..1a09b4b 100644 --- a/db/statedb/txprocessors_test.go +++ b/db/statedb/txprocessors_test.go @@ -13,6 +13,7 @@ import ( "github.com/hermeznetwork/hermez-node/common" "github.com/hermeznetwork/hermez-node/log" "github.com/hermeznetwork/hermez-node/test/til" + "github.com/iden3/go-iden3-crypto/babyjub" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) @@ -298,7 +299,7 @@ func TestProcessTxsSynchronizer(t *testing.T) { NLevels: 32, MaxFeeTx: 64, MaxTx: 512, - MaxL1Tx: 16, + MaxL1Tx: 32, } // Process the 1st batch, which contains the L1CoordinatorTxs necessary @@ -535,7 +536,7 @@ func TestZKInputsGeneration(t *testing.T) { s, err := json.Marshal(ptOut.ZKInputs) require.Nil(t, err) debug := false - debug = true + // debug = true if debug { fmt.Println(string(s)) } @@ -593,16 +594,24 @@ func TestCircomTest(t *testing.T) { require.Nil(t, err) defer assert.Nil(t, os.RemoveAll(dir)) - sdb, err := NewStateDB(dir, TypeBatchBuilder, 8) + nLevels := 16 + + sdb, err := NewStateDB(dir, TypeBatchBuilder, nLevels) assert.Nil(t, err) // same values than in the js test - bjj0, err := common.BJJFromStringWithChecksum("21b0a1688b37f77b1d1d5539ec3b826db5ac78b2513f574a04c50a7d4f8246d7") - assert.Nil(t, err) + // skJsHex is equivalent to the 0000...0001 js private key in commonjs + skJsHex := "7eb258e61862aae75c6c1d1f7efae5006ffc9e4d5596a6ff95f3df4ea209ea7f" + skJs, err := hex.DecodeString(skJsHex) + require.Nil(t, err) + var sk0 babyjub.PrivateKey + copy(sk0[:], skJs) + bjj0 := sk0.Public() + assert.Equal(t, "d746824f7d0ac5044a573f51b278acb56d823bec39551d1d7bf7378b68a1b021", bjj0.String()) + l1Txs := []common.L1Tx{ { - FromIdx: 0, - // LoadAmount: big.NewInt(10400), + FromIdx: 0, LoadAmount: big.NewInt(16000000), Amount: big.NewInt(0), TokenID: 1, @@ -620,17 +629,26 @@ func TestCircomTest(t *testing.T) { TokenID: 1, Amount: big.NewInt(1000), Nonce: 0, - Fee: 126, + Fee: 0, Type: common.TxTypeTransfer, }, } + toSign, err := l2Txs[0].HashToSign() + require.Nil(t, err) + sig := sk0.SignPoseidon(toSign) + l2Txs[0].Signature = sig.Compress() + ptc := ProcessTxsConfig{ - NLevels: 8, - MaxFeeTx: 2, - MaxTx: 5, + NLevels: uint32(nLevels), + MaxTx: 3, MaxL1Tx: 2, + MaxFeeTx: 2, } + // skip first batch to do the test with BatchNum=1 + _, err = sdb.ProcessTxs(ptc, nil, nil, nil, nil) + require.Nil(t, err) + ptOut, err := sdb.ProcessTxs(ptc, nil, l1Txs, nil, l2Txs) require.Nil(t, err) @@ -643,13 +661,15 @@ func TestCircomTest(t *testing.T) { // check that there no exist more accounts _, err = sdb.GetAccount(common.Idx(257)) require.NotNil(t, err) - ptOut.ZKInputs.FeeIdxs[0] = common.Idx(256).BigInt() s, err := json.Marshal(ptOut.ZKInputs) require.Nil(t, err) + debug := false + // debug = true if debug { fmt.Println("\nCopy&Paste into js circom test:\n let zkInput = JSON.parse(`" + string(s) + "`);") + // fmt.Println("\nZKInputs json:\n echo '" + string(s) + "' | jq") h, err := ptOut.ZKInputs.HashGlobalData() require.Nil(t, err) @@ -661,6 +681,10 @@ func TestCircomTest(t *testing.T) { `, h.String()) fmt.Println("") } + + // the 'expected' data has been checked with the circom circuits + expected := `{"auxFromIdx":["256","0","0"],"auxToIdx":["0","0","0"],"ay1":["15238403086306505038849621710779816852318505119327426213168494964113886299863","15238403086306505038849621710779816852318505119327426213168494964113886299863","0"],"ay2":["0","15238403086306505038849621710779816852318505119327426213168494964113886299863","0"],"ay3":["0","0"],"balance1":["16000000","16000000","0"],"balance2":["0","15999000","0"],"balance3":["0","0"],"currentNumBatch":"1","ethAddr1":["721457446580647751014191829380889690493307935711","721457446580647751014191829380889690493307935711","0"],"ethAddr2":["0","721457446580647751014191829380889690493307935711","0"],"ethAddr3":["0","0"],"feeIdxs":["0","0"],"feePlanTokens":["0","0"],"fromBjjCompressed":[["1","1","1","0","1","0","1","1","0","1","1","0","0","0","1","0","0","1","0","0","0","0","0","1","1","1","1","1","0","0","1","0","1","0","1","1","1","1","1","0","0","1","0","1","0","0","0","0","1","0","1","0","0","0","1","1","0","0","1","0","0","0","0","0","0","1","0","1","0","0","1","0","1","1","1","0","1","0","1","0","1","1","1","1","1","1","0","0","1","0","0","0","1","0","1","0","0","1","0","0","1","1","0","1","0","0","0","1","1","1","1","0","0","0","1","1","0","1","0","1","1","0","1","0","1","1","0","1","1","0","1","1","0","1","1","0","0","1","0","0","0","0","0","1","1","1","0","1","1","1","0","0","0","0","1","1","0","1","1","1","1","0","0","1","1","1","0","0","1","0","1","0","1","0","1","0","1","0","1","1","1","0","0","0","1","0","1","1","1","0","0","0","1","1","0","1","1","1","1","0","1","1","1","0","1","1","1","1","1","1","1","0","1","1","0","0","1","1","0","1","0","0","0","1","0","0","0","1","0","1","1","0","1","0","0","0","0","1","0","1","0","0","0","0","1","1","0","1","1","0","0","0","0","1","0","0"],["0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0"],["0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0"]],"fromEthAddr":["721457446580647751014191829380889690493307935711","0","0"],"fromIdx":["0","256","0"],"globalChainID":"0","imAccFeeOut":[["0","0"],["0","0"]],"imExitRoot":["0","0"],"imFinalAccFee":["0","0"],"imInitStateRootFee":"3212803832159212591526550848126062808026208063555125878245901046146545013161","imOnChain":["1","0"],"imOutIdx":["256","256"],"imStateRoot":["2999178063326948609414231200730958862089790119006655219527433501846141543551","3212803832159212591526550848126062808026208063555125878245901046146545013161"],"imStateRootFee":["3212803832159212591526550848126062808026208063555125878245901046146545013161"],"isOld0_1":["1","0","0"],"isOld0_2":["0","0","0"],"loadAmountF":["10400","0","0"],"maxNumBatch":["0","0","0"],"newAccount":["1","0","0"],"newExit":["0","0","0"],"nonce1":["0","0","0"],"nonce2":["0","1","0"],"nonce3":["0","0"],"oldKey1":["0","0","0"],"oldKey2":["0","0","0"],"oldLastIdx":"255","oldStateRoot":"0","oldValue1":["0","0","0"],"oldValue2":["0","0","0"],"onChain":["1","0","0"],"r8x":["0","13339118088097183560380359255316479838355724395928453439485234854234470298884","0"],"r8y":["0","12062876403986777372637801733000285846673058725183957648593976028822138986587","0"],"rqOffset":["0","0","0"],"rqToBjjAy":["0","0","0"],"rqToEthAddr":["0","0","0"],"rqTxCompressedDataV2":["0","0","0"],"s":["0","1429292460142966038093363510339656828866419125109324886747095533117015974779","0"],"siblings1":[["0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0"],["0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0"],["0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0"]],"siblings2":[["0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0"],["0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0"],["0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0"]],"siblings3":[["0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0"],["0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0"]],"sign1":["0","0","0"],"sign2":["0","0","0"],"sign3":["0","0"],"toBjjAy":["0","0","0"],"toEthAddr":["0","0","0"],"toIdx":["0","256","0"],"tokenID1":["1","1","0"],"tokenID2":["0","1","0"],"tokenID3":["0","0"],"txCompressedData":["1461501637330902918203684832716283019659255211535","1483802382529433561627630154640673862706524841487","3322668559"],"txCompressedDataV2":["0","5271525021049092038181634317484288","0"]}` + assert.Equal(t, expected, string(s)) } func TestZKInputsHashTestVector0(t *testing.T) { diff --git a/go.mod b/go.mod index 4227a8d..be2ca86 100644 --- a/go.mod +++ b/go.mod @@ -13,8 +13,8 @@ require ( github.com/go-sql-driver/mysql v1.5.0 // indirect github.com/gobuffalo/packr/v2 v2.8.0 github.com/hermeznetwork/tracerr v0.3.1-0.20201126162137-de9930d0cf29 - github.com/iden3/go-iden3-crypto v0.0.6-0.20201016142444-94e92e88fb4e - github.com/iden3/go-merkletree v0.0.0-20201103115630-ad30c8309b44 + github.com/iden3/go-iden3-crypto v0.0.6-0.20201203095229-821a601d2002 + github.com/iden3/go-merkletree v0.0.0-20201203095330-4a8397a45644 github.com/jinzhu/copier v0.0.0-20190924061706-b57f9002281a github.com/jmoiron/sqlx v1.2.1-0.20200615141059-0794cb1f47ee github.com/joho/godotenv v1.3.0 @@ -38,5 +38,3 @@ require ( gopkg.in/go-playground/validator.v9 v9.29.1 honnef.co/go/tools v0.0.1-2020.1.5 // indirect ) - -// replace github.com/russross/meddler => /home/dev/git/iden3/hermez/meddler diff --git a/go.sum b/go.sum index ff0fd5c..2373e5f 100644 --- a/go.sum +++ b/go.sum @@ -323,10 +323,14 @@ github.com/iden3/go-iden3-crypto v0.0.6-0.20200819064831-09d161e9f670 h1:gNBFu/W github.com/iden3/go-iden3-crypto v0.0.6-0.20200819064831-09d161e9f670/go.mod h1:oBgthFLboAWi9feaBUFy7OxEcyn9vA1khHSL/WwWFyg= github.com/iden3/go-iden3-crypto v0.0.6-0.20201016142444-94e92e88fb4e h1:DvzTgAkzfcW8l4mHgEaMv2hgDTlisym/gGNNTNKqnpQ= github.com/iden3/go-iden3-crypto v0.0.6-0.20201016142444-94e92e88fb4e/go.mod h1:oBgthFLboAWi9feaBUFy7OxEcyn9vA1khHSL/WwWFyg= +github.com/iden3/go-iden3-crypto v0.0.6-0.20201203095229-821a601d2002 h1:f2twuL20aAqq1TlSdfQgL5r68hKjB/ioQdSctREQLuY= +github.com/iden3/go-iden3-crypto v0.0.6-0.20201203095229-821a601d2002/go.mod h1:oBgthFLboAWi9feaBUFy7OxEcyn9vA1khHSL/WwWFyg= github.com/iden3/go-merkletree v0.0.0-20200902123354-eeb949f8c334 h1:FQngDJKiwM6i4kHlVFvSpJa9sO+QvZ7C+GqoPWe+5BI= github.com/iden3/go-merkletree v0.0.0-20200902123354-eeb949f8c334/go.mod h1:MRe6i0mi2oDVUzgBIHsNRE6XAg8EBuqIQZMsd+do+dU= github.com/iden3/go-merkletree v0.0.0-20201103115630-ad30c8309b44 h1:d6AbzJWWUosTpjb6Ab+I0bMO4UPY+u/HgkOdhksxDgY= github.com/iden3/go-merkletree v0.0.0-20201103115630-ad30c8309b44/go.mod h1:MRe6i0mi2oDVUzgBIHsNRE6XAg8EBuqIQZMsd+do+dU= +github.com/iden3/go-merkletree v0.0.0-20201203095330-4a8397a45644 h1:obSehuklDMDpmQ4j0d6RxU70bjRjEWlGlkO13CKp8Fw= +github.com/iden3/go-merkletree v0.0.0-20201203095330-4a8397a45644/go.mod h1:MRe6i0mi2oDVUzgBIHsNRE6XAg8EBuqIQZMsd+do+dU= github.com/iden3/go-wasm3 v0.0.1/go.mod h1:j+TcAB94Dfrjlu5kJt83h2OqAU+oyNUTwNZnQyII1sI= github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= github.com/influxdata/influxdb v1.2.3-0.20180221223340-01288bdb0883/go.mod h1:qZna6X/4elxqT3yI9iZYdZrWWdeFOOprn86kgg4+IzY= diff --git a/test/til/lang.go b/test/til/lang.go index ee2eb40..7007340 100644 --- a/test/til/lang.go +++ b/test/til/lang.go @@ -42,12 +42,14 @@ var TypeNewBatchL1 common.TxType = "InstrTypeNewBatchL1" var TypeNewBlock common.TxType = "InstrTypeNewBlock" // TypeAddToken is used for testing purposes only, and represents the -// common.TxType of a new Token regsitration -// It has 'nolint:gosec' as the string 'Token' triggers gosec as a potential leaked Token (which is not the case) +// common.TxType of a new Token regsitration. +// It has 'nolint:gosec' as the string 'Token' triggers gosec as a potential +// leaked Token (which is not the case). var TypeAddToken common.TxType = "InstrTypeAddToken" //nolint:gosec -// TxTypeCreateAccountDepositCoordinator is used for testing purposes only, and represents the -// common.TxType of a create acount deposit made by the coordinator +// TxTypeCreateAccountDepositCoordinator is used for testing purposes only, +// and represents the common.TxType of a create acount deposit made by the +// coordinator var TxTypeCreateAccountDepositCoordinator common.TxType = "TypeCreateAccountDepositCoordinator" //nolint diff --git a/test/til/txs.go b/test/til/txs.go index 2b92a1f..fbd5e2d 100644 --- a/test/til/txs.go +++ b/test/til/txs.go @@ -57,7 +57,8 @@ type Context struct { LastRegisteredTokenID common.TokenID l1CreatedAccounts map[string]*Account // (Name, TokenID) -> *Account - // rollupConstMaxL1UserTx Maximum L1-user transactions allowed to be queued in a batch + // rollupConstMaxL1UserTx Maximum L1-user transactions allowed to be + // queued in a batch rollupConstMaxL1UserTx int idx int @@ -146,8 +147,8 @@ type L2Tx struct { L2Tx common.L2Tx } -// GenerateBlocks returns an array of BlockData for a given set made of a string. It uses the -// users (keys & nonces) of the Context. +// GenerateBlocks returns an array of BlockData for a given set made of a +// string. It uses the users (keys & nonces) of the Context. func (tc *Context) GenerateBlocks(set string) ([]common.BlockData, error) { parser := newParser(strings.NewReader(set)) parsedSet, err := parser.parse() @@ -164,8 +165,8 @@ func (tc *Context) GenerateBlocks(set string) ([]common.BlockData, error) { return tc.generateBlocks() } -// GenerateBlocksFromInstructions returns an array of BlockData for a given set made of instructions. It uses the -// users (keys & nonces) of the Context. +// GenerateBlocksFromInstructions returns an array of BlockData for a given set +// made of instructions. It uses the users (keys & nonces) of the Context. func (tc *Context) GenerateBlocksFromInstructions(set []Instruction) ([]common.BlockData, error) { userNames := []string{} addedNames := make(map[string]bool) @@ -537,8 +538,8 @@ func (tc *Context) checkIfTokenIsRegistered(inst Instruction) error { return nil } -// GeneratePoolL2Txs returns an array of common.PoolL2Tx from a given set made of a string. It -// uses the users (keys) of the Context. +// GeneratePoolL2Txs returns an array of common.PoolL2Tx from a given set made +// of a string. It uses the users (keys) of the Context. func (tc *Context) GeneratePoolL2Txs(set string) ([]common.PoolL2Tx, error) { parser := newParser(strings.NewReader(set)) parsedSet, err := parser.parse() @@ -555,8 +556,8 @@ func (tc *Context) GeneratePoolL2Txs(set string) ([]common.PoolL2Tx, error) { return tc.generatePoolL2Txs() } -// GeneratePoolL2TxsFromInstructions returns an array of common.PoolL2Tx from a given set made of instructions. It -// uses the users (keys) of the Context. +// GeneratePoolL2TxsFromInstructions returns an array of common.PoolL2Tx from a +// given set made of instructions. It uses the users (keys) of the Context. func (tc *Context) GeneratePoolL2TxsFromInstructions(set []Instruction) ([]common.PoolL2Tx, error) { userNames := []string{} addedNames := make(map[string]bool) @@ -775,7 +776,8 @@ func (tc *Context) FillBlocksForgedL1UserTxs(blocks []common.BlockData) error { } // FillBlocksExtra fills extra fields not generated by til in each block, so -// that the blockData is closer to what the HistoryDB stores. The filled fields are: +// that the blockData is closer to what the HistoryDB stores. The filled +// fields are: // - blocks[].Rollup.Batch.EthBlockNum // - blocks[].Rollup.Batch.ForgerAddr // - blocks[].Rollup.Batch.ForgeL1TxsNum