diff --git a/batchbuilder/batchbuilder.go b/batchbuilder/batchbuilder.go new file mode 100644 index 0000000..23be0ea --- /dev/null +++ b/batchbuilder/batchbuilder.go @@ -0,0 +1,231 @@ +package batchbuilder + +import ( + ethCommon "github.com/ethereum/go-ethereum/common" + "github.com/hermeznetwork/hermez-node/common" + "github.com/iden3/go-iden3-crypto/babyjub" + "github.com/iden3/go-merkletree" + "github.com/iden3/go-merkletree/db" + "github.com/iden3/go-merkletree/db/memory" +) + +// ConfigCircuit contains the circuit configuration +type ConfigCircuit struct { + TxsMax uint64 + L1TxsMax uint64 + SMTLevelsMax uint64 +} + +// BatchBuilder implements the batch builder type, which contains the functionallities +type BatchBuilder struct { + StateDB db.Storage // where the MTs will be stored by the Synchronizer + idx uint64 + mt *merkletree.MerkleTree + configCircuits []ConfigCircuit +} + +// ConfigBatch contains the batch configuration +type ConfigBatch struct { + CoordinatorAddress ethCommon.Address +} + +// NewBatchBuilder constructs a new BatchBuilder, and executes the bb.Reset +// method +func NewBatchBuilder(stateDB db.Storage, configCircuits []ConfigCircuit, batchNum int, idx, nLevels uint64) (*BatchBuilder, error) { + localMt, err := merkletree.NewMerkleTree(memory.NewMemoryStorage(), int(nLevels)) + if err != nil { + return nil, err + } + bb := BatchBuilder{ + StateDB: stateDB, + idx: idx, + mt: localMt, + configCircuits: configCircuits, + } + + err = bb.Reset(batchNum, idx, true) + return &bb, err +} + +// Reset tells the BatchBuilder to reset it's internal state to the required +// `batchNum`. If `fromSynchronizer` is true, the BatchBuilder must take a +// copy of the rollup state from the Synchronizer at that `batchNum`, otherwise +// it can just roll back the internal copy. +func (bb *BatchBuilder) Reset(batchNum int, idx uint64, fromSynchronizer bool) error { + // TODO + return nil +} + +// BuildBatch takes the transactions and returns the common.ZKInputs of the next batch +func (bb *BatchBuilder) BuildBatch(configBatch ConfigBatch, l1usertxs, l1coordinatortxs []common.L1Tx, l2txs []common.L2Tx, tokenIDs []common.TokenID) (*common.ZKInputs, error) { + for _, tx := range l1usertxs { + err := bb.processL1Tx(tx) + if err != nil { + return nil, err + } + } + for _, tx := range l1coordinatortxs { + err := bb.processL1Tx(tx) + if err != nil { + return nil, err + } + } + for _, tx := range l2txs { + switch tx.Type { + case common.TxTypeTransfer: + // go to the MT leaf of sender and receiver, and update + // balance & nonce + err := bb.applyTransfer(tx.Tx) + if err != nil { + return nil, err + } + case common.TxTypeExit: + // execute exit flow + default: + } + } + + return nil, nil +} + +func (bb *BatchBuilder) processL1Tx(tx common.L1Tx) error { + switch tx.Type { + case common.TxTypeForceTransfer, common.TxTypeTransfer: + // go to the MT leaf of sender and receiver, and update balance + // & nonce + err := bb.applyTransfer(tx.Tx) + if err != nil { + return err + } + case common.TxTypeCreateAccountDeposit: + // add new leaf to the MT, update balance of the MT leaf + err := bb.applyCreateLeaf(tx) + if err != nil { + return err + } + case common.TxTypeDeposit: + // update balance of the MT leaf + err := bb.applyDeposit(tx, false) + if err != nil { + return err + } + case common.TxTypeDepositAndTransfer: + // update balance in MT leaf, update balance & nonce of sender + // & receiver + err := bb.applyDeposit(tx, true) + if err != nil { + return err + } + case common.TxTypeCreateAccountDepositAndTransfer: + // add new leaf to the merkletree, update balance in MT leaf, + // update balance & nonce of sender & receiver + err := bb.applyCreateLeaf(tx) + if err != nil { + return err + } + err = bb.applyTransfer(tx.Tx) + if err != nil { + return err + } + case common.TxTypeExit: + // execute exit flow + default: + } + + return nil +} + +// applyCreateLeaf creates a new leaf in the leaf of the depositer, it stores +// the deposit value +func (bb *BatchBuilder) applyCreateLeaf(tx common.L1Tx) error { + leaf := common.Leaf{ + TokenID: tx.TokenID, + Nonce: 0, // TODO check w spec: always that a new leaf is created nonce is at 0 + Balance: tx.LoadAmount, + Sign: babyjub.PointCoordSign(tx.FromBJJ.X), + Ay: tx.FromBJJ.Y, + EthAddr: tx.FromEthAddr, + } + + v, err := leaf.HashValue() + if err != nil { + return err + } + dbTx, err := bb.mt.DB().NewTx() + if err != nil { + return err + } + + err = bb.CreateBalance(dbTx, common.Idx(bb.idx+1), leaf) + if err != nil { + return err + } + leafBytes, err := leaf.Bytes() + if err != nil { + return err + } + dbTx.Put(v.Bytes(), leafBytes[:]) + + // if everything is fine, do dbTx & increment idx + if err := dbTx.Commit(); err != nil { + return err + } + bb.idx = bb.idx + 1 + return nil +} + +// applyDeposit updates the balance in the leaf of the depositer, if andTransfer parameter is set to true, the method will also apply the Transfer of the L1Tx/DepositAndTransfer +func (bb *BatchBuilder) applyDeposit(tx common.L1Tx, andTransfer bool) error { + dbTx, err := bb.mt.DB().NewTx() + if err != nil { + return err + } + + // deposit + err = bb.UpdateBalance(dbTx, tx.FromIdx, tx.LoadAmount, false) + if err != nil { + return err + } + + // in case that the tx is a L1Tx>DepositAndTransfer + if andTransfer { + // transact + err = bb.UpdateBalance(dbTx, tx.FromIdx, tx.Tx.Amount, true) + if err != nil { + return err + } + err = bb.UpdateBalance(dbTx, tx.ToIdx, tx.Tx.Amount, false) + if err != nil { + return err + } + } + + if err := dbTx.Commit(); err != nil { + return err + } + return nil +} + +// applyTransfer updates the balance & nonce in the leaf of the sender, and the +// balance in the leaf of the receiver +func (bb *BatchBuilder) applyTransfer(tx common.Tx) error { + dbTx, err := bb.mt.DB().NewTx() + if err != nil { + return err + } + + // transact + err = bb.UpdateBalance(dbTx, tx.FromIdx, tx.Amount, true) + if err != nil { + return err + } + err = bb.UpdateBalance(dbTx, tx.ToIdx, tx.Amount, false) + if err != nil { + return err + } + + if err := dbTx.Commit(); err != nil { + return err + } + return nil +} diff --git a/batchbuilder/batchbuilder_test.go b/batchbuilder/batchbuilder_test.go new file mode 100644 index 0000000..4ed5134 --- /dev/null +++ b/batchbuilder/batchbuilder_test.go @@ -0,0 +1,29 @@ +package batchbuilder + +import ( + "fmt" + "testing" + + "github.com/iden3/go-merkletree/db/memory" + "github.com/stretchr/testify/assert" +) + +// func genTxs(n int) common.Tx { +// return common.Tx{} +// } +// func genL1Txs(n int) []common.L1Tx { +// +// return nil +// } +// func genL2Txs(n int) []common.L2Tx { +// +// return nil +// } + +func TestBatchBuilder(t *testing.T) { + stateDB := memory.NewMemoryStorage() + + bb, err := NewBatchBuilder(stateDB, nil, 0, 0, 32) + assert.Nil(t, err) + fmt.Println(bb) +} diff --git a/batchbuilder/state.go b/batchbuilder/state.go new file mode 100644 index 0000000..be6ca63 --- /dev/null +++ b/batchbuilder/state.go @@ -0,0 +1,85 @@ +package batchbuilder + +import ( + "math/big" + + "github.com/hermeznetwork/hermez-node/common" + "github.com/iden3/go-merkletree/db" +) + +// TODO next iteration move the methods of this file into StateDB, which Synchronizer will use in the disk DB, and BatchBuilder will use with the MemoryDB + +// GetBalance returns the balance for a given Idx from the DB +func (bb *BatchBuilder) GetBalance(tx db.Tx, idx common.Idx) (*common.Leaf, error) { + idxBytes := idx.Bytes() + vBytes, err := tx.Get(idxBytes[:]) + if err != nil { + return nil, err + } + var b [32 * common.NLEAFELEMS]byte + copy(b[:], vBytes) + leaf, err := common.LeafFromBytes(b) + if err != nil { + return nil, err + } + return leaf, nil +} + +// CreateBalance stores the Leaf into the Idx position in the MerkleTree, also adds db entry for the Leaf value +func (bb *BatchBuilder) CreateBalance(tx db.Tx, idx common.Idx, leaf common.Leaf) error { + // store at the DB the key: v, and value: leaf.Bytes() + v, err := leaf.HashValue() + if err != nil { + return err + } + leafBytes, err := leaf.Bytes() + if err != nil { + return err + } + + // store the Leaf value + tx.Put(v.Bytes(), leafBytes[:]) + // Add k & v into the MT + err = bb.mt.Add(idx.BigInt(), v) + if err != nil { + return err + } + + return nil +} + +// UpdateBalance updates the balance of the leaf of a given Idx. +// If sending==true: will substract the amount, if sending==false will add the ammount +func (bb *BatchBuilder) UpdateBalance(tx db.Tx, idx common.Idx, amount *big.Int, sending bool) error { + leaf, err := bb.GetBalance(tx, idx) + if err != nil { + return err + } + + // TODO add checks that the numbers are correct and there is no missing value neither impossible values + if sending { + leaf.Balance = new(big.Int).Sub(leaf.Balance, amount) + } else { + leaf.Balance = new(big.Int).Add(leaf.Balance, amount) + } + + // store at the DB the key: v, and value: leaf.Bytes() + v, err := leaf.HashValue() + if err != nil { + return err + } + leafBytes, err := leaf.Bytes() + if err != nil { + return err + } + + // store the Leaf value + tx.Put(v.Bytes(), leafBytes[:]) + // Add k & v into the MT + err = bb.mt.Update(idx.BigInt(), v) + if err != nil { + return err + } + + return nil +} diff --git a/common/leaf.go b/common/leaf.go index 9cb4e73..156c750 100644 --- a/common/leaf.go +++ b/common/leaf.go @@ -4,28 +4,30 @@ import ( "bytes" "encoding/binary" "fmt" - "math" "math/big" eth "github.com/ethereum/go-ethereum/common" + "github.com/iden3/go-iden3-crypto/poseidon" cryptoUtils "github.com/iden3/go-iden3-crypto/utils" ) +const NLEAFELEMS = 4 + // Leaf is the data structure stored in the Leaf of the MerkleTree type Leaf struct { TokenID TokenID Nonce uint64 // max of 40 bits used Balance *big.Int // max of 192 bits used - Ax *big.Int + Sign bool Ay *big.Int EthAddr eth.Address } // Bytes returns the bytes representing the Leaf, in a way that each BigInt is represented by 32 bytes, in spite of the BigInt could be represented in less bytes (due a small big.Int), so in this way each BigInt is always 32 bytes and can be automatically parsed from a byte array. -func (l *Leaf) Bytes() ([32 * 5]byte, error) { - var b [32 * 5]byte +func (l *Leaf) Bytes() ([32 * NLEAFELEMS]byte, error) { + var b [32 * NLEAFELEMS]byte - if l.Nonce >= uint64(math.Pow(2, 40)) { + if l.Nonce > 0xffffffffff { return b, fmt.Errorf("%s Nonce", ErrNumOverflow) } if len(l.Balance.Bytes()) > 24 { @@ -39,17 +41,19 @@ func (l *Leaf) Bytes() ([32 * 5]byte, error) { copy(b[0:4], tokenIDBytes[:]) copy(b[4:9], nonceBytes[:]) + if l.Sign { + b[10] = 1 + } copy(b[32:64], SwapEndianness(l.Balance.Bytes())) // SwapEndianness, as big.Int uses BigEndian - copy(b[64:96], SwapEndianness(l.Ax.Bytes())) - copy(b[96:128], SwapEndianness(l.Ay.Bytes())) - copy(b[128:148], l.EthAddr.Bytes()) + copy(b[64:96], SwapEndianness(l.Ay.Bytes())) + copy(b[96:116], l.EthAddr.Bytes()) return b, nil } // BigInts returns the [5]*big.Int, where each *big.Int is inside the Finite Field -func (l *Leaf) BigInts() ([5]*big.Int, error) { - e := [5]*big.Int{} +func (l *Leaf) BigInts() ([NLEAFELEMS]*big.Int, error) { + e := [NLEAFELEMS]*big.Int{} b, err := l.Bytes() if err != nil { @@ -60,47 +64,54 @@ func (l *Leaf) BigInts() ([5]*big.Int, error) { e[1] = new(big.Int).SetBytes(SwapEndianness(b[32:64])) e[2] = new(big.Int).SetBytes(SwapEndianness(b[64:96])) e[3] = new(big.Int).SetBytes(SwapEndianness(b[96:128])) - e[4] = new(big.Int).SetBytes(SwapEndianness(b[128:160])) return e, nil } +// HashValue returns the value of the Leaf, which is the Poseidon hash of its *big.Int representation +func (l *Leaf) HashValue() (*big.Int, error) { + toHash := [poseidon.T]*big.Int{} + lBI, err := l.BigInts() + if err != nil { + return nil, err + } + copy(toHash[:], lBI[:]) + + v, err := poseidon.Hash(toHash) + return v, err +} + // LeafFromBigInts returns a Leaf from a [5]*big.Int -func LeafFromBigInts(e [5]*big.Int) (*Leaf, error) { +func LeafFromBigInts(e [NLEAFELEMS]*big.Int) (*Leaf, error) { if !cryptoUtils.CheckBigIntArrayInField(e[:]) { return nil, ErrNotInFF } - var b [32 * 5]byte + var b [32 * NLEAFELEMS]byte copy(b[0:32], SwapEndianness(e[0].Bytes())) // SwapEndianness, as big.Int uses BigEndian copy(b[32:64], SwapEndianness(e[1].Bytes())) copy(b[64:96], SwapEndianness(e[2].Bytes())) copy(b[96:128], SwapEndianness(e[3].Bytes())) - copy(b[128:160], SwapEndianness(e[4].Bytes())) return LeafFromBytes(b) } // LeafFromBytes returns a Leaf from a byte array -func LeafFromBytes(b [32 * 5]byte) (*Leaf, error) { +func LeafFromBytes(b [32 * NLEAFELEMS]byte) (*Leaf, error) { tokenID := binary.LittleEndian.Uint32(b[0:4]) - nonce := binary.LittleEndian.Uint64(b[4:12]) - if !bytes.Equal(b[9:12], []byte{0, 0, 0}) { // alternatively: if nonce >= uint64(math.Pow(2, 40)) { - return nil, fmt.Errorf("%s Nonce", ErrNumOverflow) - } + var nonceBytes [8]byte + copy(nonceBytes[:], b[4:9]) + nonce := binary.LittleEndian.Uint64(nonceBytes[:]) + sign := b[10] == 1 balance := new(big.Int).SetBytes(SwapEndianness(b[32:56])) // b[32:56], as Balance is 192 bits (24 bytes) if !bytes.Equal(b[56:64], []byte{0, 0, 0, 0, 0, 0, 0, 0}) { return nil, fmt.Errorf("%s Balance", ErrNumOverflow) } - ax := new(big.Int).SetBytes(SwapEndianness(b[64:96])) // SwapEndianness, as big.Int uses BigEndian - ay := new(big.Int).SetBytes(SwapEndianness(b[96:128])) - ethAddr := eth.BytesToAddress(b[128:148]) + ay := new(big.Int).SetBytes(SwapEndianness(b[64:96])) + ethAddr := eth.BytesToAddress(b[96:116]) if !cryptoUtils.CheckBigIntInField(balance) { return nil, ErrNotInFF } - if !cryptoUtils.CheckBigIntInField(ax) { - return nil, ErrNotInFF - } if !cryptoUtils.CheckBigIntInField(ay) { return nil, ErrNotInFF } @@ -109,7 +120,7 @@ func LeafFromBytes(b [32 * 5]byte) (*Leaf, error) { TokenID: TokenID(tokenID), Nonce: nonce, Balance: balance, - Ax: ax, + Sign: sign, Ay: ay, EthAddr: ethAddr, } diff --git a/common/leaf_test.go b/common/leaf_test.go index 2f67a10..d51b1ab 100644 --- a/common/leaf_test.go +++ b/common/leaf_test.go @@ -17,12 +17,13 @@ func TestLeaf(t *testing.T) { TokenID: TokenID(1), Nonce: uint64(1234), Balance: big.NewInt(1000), - Ax: big.NewInt(9876), + Sign: true, Ay: big.NewInt(6789), EthAddr: ethCommon.HexToAddress("0xc58d29fA6e86E4FAe04DDcEd660d45BCf3Cb2370"), } b, err := leaf.Bytes() assert.Nil(t, err) + assert.Equal(t, byte(1), b[10]) l1, err := LeafFromBytes(b) assert.Nil(t, err) assert.Equal(t, leaf, l1) @@ -33,11 +34,10 @@ func TestLeaf(t *testing.T) { assert.True(t, cryptoUtils.CheckBigIntInField(e[1])) assert.True(t, cryptoUtils.CheckBigIntInField(e[2])) assert.True(t, cryptoUtils.CheckBigIntInField(e[3])) - assert.True(t, cryptoUtils.CheckBigIntInField(e[4])) assert.Equal(t, "1000", e[1].String()) - assert.Equal(t, "9876", e[2].String()) - assert.Equal(t, "6789", e[3].String()) + assert.Equal(t, "6789", e[2].String()) + assert.Equal(t, new(big.Int).SetBytes(SwapEndianness(leaf.EthAddr.Bytes())).String(), e[3].String()) l2, err := LeafFromBigInts(e) assert.Nil(t, err) @@ -56,7 +56,7 @@ func TestLeaf(t *testing.T) { // TokenID: TokenID(i), // Nonce: uint64(i), // Balance: big.NewInt(1000), -// Ax: big.NewInt(9876), +// Sign: true, // Ay: big.NewInt(6789), // EthAddr: address, // } @@ -72,7 +72,6 @@ func TestLeaf(t *testing.T) { // assert.True(t, cryptoUtils.CheckBigIntInField(e[1])) // assert.True(t, cryptoUtils.CheckBigIntInField(e[2])) // assert.True(t, cryptoUtils.CheckBigIntInField(e[3])) -// assert.True(t, cryptoUtils.CheckBigIntInField(e[4])) // // l2, err := LeafFromBigInts(e) // assert.Nil(t, err) @@ -85,20 +84,20 @@ func TestLeafErrNotInFF(t *testing.T) { // Q-1 should not give error r := new(big.Int).Sub(cryptoConstants.Q, big.NewInt(1)) - e := [5]*big.Int{z, z, r, r, r} + e := [NLEAFELEMS]*big.Int{z, z, r, r} _, err := LeafFromBigInts(e) assert.Nil(t, err) // Q should give error r = cryptoConstants.Q - e = [5]*big.Int{z, z, r, r, r} + e = [NLEAFELEMS]*big.Int{z, z, r, r} _, err = LeafFromBigInts(e) assert.NotNil(t, err) assert.Equal(t, ErrNotInFF, err) // Q+1 should give error r = new(big.Int).Add(cryptoConstants.Q, big.NewInt(1)) - e = [5]*big.Int{z, z, r, r, r} + e = [NLEAFELEMS]*big.Int{z, z, r, r} _, err = LeafFromBigInts(e) assert.NotNil(t, err) assert.Equal(t, ErrNotInFF, err) @@ -110,7 +109,7 @@ func TestLeafErrNumOverflowNonce(t *testing.T) { TokenID: TokenID(1), Nonce: uint64(math.Pow(2, 40) - 1), Balance: big.NewInt(1000), - Ax: big.NewInt(9876), + Sign: true, Ay: big.NewInt(6789), EthAddr: ethCommon.HexToAddress("0xc58d29fA6e86E4FAe04DDcEd660d45BCf3Cb2370"), } @@ -125,11 +124,6 @@ func TestLeafErrNumOverflowNonce(t *testing.T) { _, err = LeafFromBytes(b) assert.Nil(t, err) - - b[9] = 1 - _, err = LeafFromBytes(b) - assert.NotNil(t, err) - assert.Equal(t, fmt.Errorf("%s Nonce", ErrNumOverflow), err) } func TestLeafErrNumOverflowBalance(t *testing.T) { @@ -138,7 +132,7 @@ func TestLeafErrNumOverflowBalance(t *testing.T) { TokenID: TokenID(1), Nonce: uint64(math.Pow(2, 40) - 1), Balance: new(big.Int).Sub(new(big.Int).Exp(big.NewInt(2), big.NewInt(192), nil), big.NewInt(1)), - Ax: big.NewInt(9876), + Sign: true, Ay: big.NewInt(6789), EthAddr: ethCommon.HexToAddress("0xc58d29fA6e86E4FAe04DDcEd660d45BCf3Cb2370"), } diff --git a/common/tx.go b/common/tx.go index 58b2e20..3f2156f 100644 --- a/common/tx.go +++ b/common/tx.go @@ -1,14 +1,38 @@ package common import ( + "encoding/binary" "math/big" ) +// Idx represents the account Index in the MerkleTree +type Idx uint32 + +// Bytes returns a byte array representing the Idx +func (idx Idx) Bytes() []byte { + var b [4]byte + binary.LittleEndian.PutUint32(b[:], uint32(idx)) + return b[:] +} + +// BigInt returns a *big.Int representing the Idx +func (idx Idx) BigInt() *big.Int { + return big.NewInt(int64(idx)) +} + +// IdxFromBigInt converts a *big.Int to Idx type +func IdxFromBigInt(b *big.Int) (Idx, error) { + if b.Int64() > 0xffffffff { // 2**32-1 + return 0, ErrNumOverflow + } + return Idx(uint32(b.Int64())), nil +} + // Tx is a struct that represents a Hermez network transaction type Tx struct { TxID TxID - FromIdx uint32 - ToIdx uint32 + FromIdx Idx // FromIdx is used by L1Tx/Deposit to indicate the Idx receiver of the L1Tx.LoadAmount (deposit) + ToIdx Idx // ToIdx is ignored in L1Tx/Deposit, but used in the L1Tx/DepositAndTransfer TokenID TokenID Amount *big.Int Nonce uint64 // effective 48 bits used diff --git a/common/tx_test.go b/common/tx_test.go new file mode 100644 index 0000000..4851e5d --- /dev/null +++ b/common/tx_test.go @@ -0,0 +1,23 @@ +package common + +import ( + "math/big" + "testing" + + "github.com/stretchr/testify/assert" +) + +func TestIdx(t *testing.T) { + i := Idx(100) + assert.Equal(t, big.NewInt(100), i.BigInt()) + + i = Idx(uint32(4294967295)) + assert.Equal(t, "4294967295", i.BigInt().String()) + + b := big.NewInt(4294967296) + i, err := IdxFromBigInt(b) + assert.NotNil(t, err) + assert.Equal(t, ErrNumOverflow, err) + assert.Equal(t, Idx(0), i) + +} diff --git a/common/zk.go b/common/zk.go new file mode 100644 index 0000000..8392ca9 --- /dev/null +++ b/common/zk.go @@ -0,0 +1,56 @@ +package common + +import ( + "math/big" +) + +type ZKInputs struct { + InitialIdx uint64 + OldStRoot Hash + FeePlanCoins *big.Int + FeeTotals *big.Int + PubEthAddress *big.Int + + ImStateRoot []Hash + ImExitRoot []Hash + + ImOnChainHash []Hash + ImOnChain []*big.Int + TxData []*big.Int + + FromIdx []uint64 + ToIdX []uint64 + ToAx []*big.Int + ToAy []*big.Int + ToEthAddr []*big.Int + FromEthAddr []*big.Int + FromAx []*big.Int + FromAy []*big.Int + + RqTxData []*big.Int + LoadAmount []*big.Int + + S []*big.Int + R8x []*big.Int + R8y []*big.Int + + Ax1 []*big.Int + Ay1 []*big.Int + Amount1 []*big.Int + Nonce1 []*big.Int + EthAddr1 []*big.Int + Siblings1 [][]*big.Int + IsOld01 []*big.Int `json:"isOld0_1"` + OldKey1 []*big.Int + OldValue1 []*big.Int + + Ax2 []*big.Int + Ay2 []*big.Int + Amount2 []*big.Int + Nonce2 []*big.Int + EthAddr2 []*big.Int + Siblings2 [][]*big.Int + IsOld02 []*big.Int `json:"isOld0_2"` + OldKey2 []*big.Int + OldValue2 []*big.Int +} diff --git a/go.mod b/go.mod index 1425a09..584e13f 100644 --- a/go.mod +++ b/go.mod @@ -3,6 +3,7 @@ module github.com/hermeznetwork/hermez-node go 1.14 require ( + github.com/dghubble/sling v1.3.0 github.com/ethereum/go-ethereum v1.9.17 github.com/iden3/go-iden3-crypto v0.0.6-0.20200723082457-29a66457f0bf github.com/iden3/go-merkletree v0.0.0-20200723202738-75e24244a1e3 diff --git a/go.sum b/go.sum index 76132c8..977471c 100644 --- a/go.sum +++ b/go.sum @@ -62,6 +62,7 @@ github.com/deckarep/golang-set v0.0.0-20180603214616-504e848d77ea/go.mod h1:93vs github.com/deckarep/golang-set v1.7.1/go.mod h1:93vsz/8Wt4joVM7c2AVqh+YRMiUSc14yDtF28KmMOgQ= github.com/denisenkom/go-mssqldb v0.0.0-20191124224453-732737034ffd h1:83Wprp6ROGeiHFAP8WJdI2RoxALQYgdllERc3N5N2DM= github.com/denisenkom/go-mssqldb v0.0.0-20191124224453-732737034ffd/go.mod h1:xbL0rPBG9cCiLr28tMa8zpbdarY27NDyej4t/EjAShU= +github.com/dghubble/sling v1.3.0 h1:pZHjCJq4zJvc6qVQ5wN1jo5oNZlNE0+8T/h0XeXBUKU= github.com/dghubble/sling v1.3.0/go.mod h1:XXShWaBWKzNLhu2OxikSNFrlsvowtz4kyRuXUG7oQKY= github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ= github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no= @@ -111,6 +112,7 @@ github.com/golang/snappy v0.0.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEW github.com/golang/snappy v0.0.2-0.20200707131729-196ae77b8a26/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/go-querystring v1.0.0 h1:Xkwi/a1rcvNg1PPYe5vI8GbeBY/jrVuDX5ASuANWTrk= github.com/google/go-querystring v1.0.0/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck= github.com/google/uuid v1.0.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/gorilla/websocket v1.4.1-0.20190629185528-ae1634f6a989/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ=