mirror of
https://github.com/arnaucube/hermez-node.git
synced 2026-02-07 03:16:45 +01:00
Add StateDB & LocalStateDB
This commit is contained in:
@@ -3,7 +3,6 @@ package batchbuilder
|
|||||||
import (
|
import (
|
||||||
ethCommon "github.com/ethereum/go-ethereum/common"
|
ethCommon "github.com/ethereum/go-ethereum/common"
|
||||||
"github.com/hermeznetwork/hermez-node/common"
|
"github.com/hermeznetwork/hermez-node/common"
|
||||||
"github.com/iden3/go-iden3-crypto/babyjub"
|
|
||||||
"github.com/iden3/go-merkletree"
|
"github.com/iden3/go-merkletree"
|
||||||
"github.com/iden3/go-merkletree/db"
|
"github.com/iden3/go-merkletree/db"
|
||||||
"github.com/iden3/go-merkletree/db/memory"
|
"github.com/iden3/go-merkletree/db/memory"
|
||||||
@@ -73,7 +72,7 @@ func (bb *BatchBuilder) BuildBatch(configBatch ConfigBatch, l1usertxs, l1coordin
|
|||||||
for _, tx := range l2txs {
|
for _, tx := range l2txs {
|
||||||
switch tx.Type {
|
switch tx.Type {
|
||||||
case common.TxTypeTransfer:
|
case common.TxTypeTransfer:
|
||||||
// go to the MT leaf of sender and receiver, and update
|
// go to the MT account of sender and receiver, and update
|
||||||
// balance & nonce
|
// balance & nonce
|
||||||
err := bb.applyTransfer(tx.Tx)
|
err := bb.applyTransfer(tx.Tx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -91,33 +90,33 @@ func (bb *BatchBuilder) BuildBatch(configBatch ConfigBatch, l1usertxs, l1coordin
|
|||||||
func (bb *BatchBuilder) processL1Tx(tx common.L1Tx) error {
|
func (bb *BatchBuilder) processL1Tx(tx common.L1Tx) error {
|
||||||
switch tx.Type {
|
switch tx.Type {
|
||||||
case common.TxTypeForceTransfer, common.TxTypeTransfer:
|
case common.TxTypeForceTransfer, common.TxTypeTransfer:
|
||||||
// go to the MT leaf of sender and receiver, and update balance
|
// go to the MT account of sender and receiver, and update balance
|
||||||
// & nonce
|
// & nonce
|
||||||
err := bb.applyTransfer(tx.Tx)
|
err := bb.applyTransfer(tx.Tx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
case common.TxTypeCreateAccountDeposit:
|
case common.TxTypeCreateAccountDeposit:
|
||||||
// add new leaf to the MT, update balance of the MT leaf
|
// add new account to the MT, update balance of the MT account
|
||||||
err := bb.applyCreateLeaf(tx)
|
err := bb.applyCreateLeaf(tx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
case common.TxTypeDeposit:
|
case common.TxTypeDeposit: // TODO check if this type will ever exist, or will be TxTypeDepositAndTransfer with transfer 0 value
|
||||||
// update balance of the MT leaf
|
// update balance of the MT account
|
||||||
err := bb.applyDeposit(tx, false)
|
err := bb.applyDeposit(tx, false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
case common.TxTypeDepositAndTransfer:
|
case common.TxTypeDepositAndTransfer:
|
||||||
// update balance in MT leaf, update balance & nonce of sender
|
// update balance in MT account, update balance & nonce of sender
|
||||||
// & receiver
|
// & receiver
|
||||||
err := bb.applyDeposit(tx, true)
|
err := bb.applyDeposit(tx, true)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
case common.TxTypeCreateAccountDepositAndTransfer:
|
case common.TxTypeCreateAccountDepositAndTransfer:
|
||||||
// add new leaf to the merkletree, update balance in MT leaf,
|
// add new account to the merkletree, update balance in MT account,
|
||||||
// update balance & nonce of sender & receiver
|
// update balance & nonce of sender & receiver
|
||||||
err := bb.applyCreateLeaf(tx)
|
err := bb.applyCreateLeaf(tx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -135,19 +134,18 @@ func (bb *BatchBuilder) processL1Tx(tx common.L1Tx) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// applyCreateLeaf creates a new leaf in the leaf of the depositer, it stores
|
// applyCreateLeaf creates a new account in the account of the depositer, it stores
|
||||||
// the deposit value
|
// the deposit value
|
||||||
func (bb *BatchBuilder) applyCreateLeaf(tx common.L1Tx) error {
|
func (bb *BatchBuilder) applyCreateLeaf(tx common.L1Tx) error {
|
||||||
leaf := common.Leaf{
|
account := common.Account{
|
||||||
TokenID: tx.TokenID,
|
TokenID: tx.TokenID,
|
||||||
Nonce: 0, // TODO check w spec: always that a new leaf is created nonce is at 0
|
Nonce: 0,
|
||||||
Balance: tx.LoadAmount,
|
Balance: tx.LoadAmount,
|
||||||
Sign: babyjub.PointCoordSign(tx.FromBJJ.X),
|
PublicKey: &tx.FromBJJ,
|
||||||
Ay: tx.FromBJJ.Y,
|
|
||||||
EthAddr: tx.FromEthAddr,
|
EthAddr: tx.FromEthAddr,
|
||||||
}
|
}
|
||||||
|
|
||||||
v, err := leaf.HashValue()
|
v, err := account.HashValue()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -156,15 +154,15 @@ func (bb *BatchBuilder) applyCreateLeaf(tx common.L1Tx) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
err = bb.CreateBalance(dbTx, common.Idx(bb.idx+1), leaf)
|
err = bb.CreateBalance(dbTx, common.Idx(bb.idx+1), account)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
leafBytes, err := leaf.Bytes()
|
accountBytes, err := account.Bytes()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
dbTx.Put(v.Bytes(), leafBytes[:])
|
dbTx.Put(v.Bytes(), accountBytes[:])
|
||||||
|
|
||||||
// if everything is fine, do dbTx & increment idx
|
// if everything is fine, do dbTx & increment idx
|
||||||
if err := dbTx.Commit(); err != nil {
|
if err := dbTx.Commit(); err != nil {
|
||||||
@@ -174,7 +172,7 @@ func (bb *BatchBuilder) applyCreateLeaf(tx common.L1Tx) error {
|
|||||||
return nil
|
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
|
// applyDeposit updates the balance in the account 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 {
|
func (bb *BatchBuilder) applyDeposit(tx common.L1Tx, andTransfer bool) error {
|
||||||
dbTx, err := bb.mt.DB().NewTx()
|
dbTx, err := bb.mt.DB().NewTx()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -206,8 +204,8 @@ func (bb *BatchBuilder) applyDeposit(tx common.L1Tx, andTransfer bool) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// applyTransfer updates the balance & nonce in the leaf of the sender, and the
|
// applyTransfer updates the balance & nonce in the account of the sender, and the
|
||||||
// balance in the leaf of the receiver
|
// balance in the account of the receiver
|
||||||
func (bb *BatchBuilder) applyTransfer(tx common.Tx) error {
|
func (bb *BatchBuilder) applyTransfer(tx common.Tx) error {
|
||||||
dbTx, err := bb.mt.DB().NewTx()
|
dbTx, err := bb.mt.DB().NewTx()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ import (
|
|||||||
// 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
|
// 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
|
// GetBalance returns the balance for a given Idx from the DB
|
||||||
func (bb *BatchBuilder) GetBalance(tx db.Tx, idx common.Idx) (*common.Leaf, error) {
|
func (bb *BatchBuilder) GetBalance(tx db.Tx, idx common.Idx) (*common.Account, error) {
|
||||||
idxBytes := idx.Bytes()
|
idxBytes := idx.Bytes()
|
||||||
vBytes, err := tx.Get(idxBytes[:])
|
vBytes, err := tx.Get(idxBytes[:])
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -18,15 +18,15 @@ func (bb *BatchBuilder) GetBalance(tx db.Tx, idx common.Idx) (*common.Leaf, erro
|
|||||||
}
|
}
|
||||||
var b [32 * common.NLEAFELEMS]byte
|
var b [32 * common.NLEAFELEMS]byte
|
||||||
copy(b[:], vBytes)
|
copy(b[:], vBytes)
|
||||||
leaf, err := common.LeafFromBytes(b)
|
leaf, err := common.AccountFromBytes(b)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
return leaf, nil
|
return leaf, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// CreateBalance stores the Leaf into the Idx position in the MerkleTree, also adds db entry for the Leaf value
|
// CreateBalance stores the Account into the Idx position in the MerkleTree, also adds db entry for the Account value
|
||||||
func (bb *BatchBuilder) CreateBalance(tx db.Tx, idx common.Idx, leaf common.Leaf) error {
|
func (bb *BatchBuilder) CreateBalance(tx db.Tx, idx common.Idx, leaf common.Account) error {
|
||||||
// store at the DB the key: v, and value: leaf.Bytes()
|
// store at the DB the key: v, and value: leaf.Bytes()
|
||||||
v, err := leaf.HashValue()
|
v, err := leaf.HashValue()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -37,7 +37,7 @@ func (bb *BatchBuilder) CreateBalance(tx db.Tx, idx common.Idx, leaf common.Leaf
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// store the Leaf value
|
// store the Account value
|
||||||
tx.Put(v.Bytes(), leafBytes[:])
|
tx.Put(v.Bytes(), leafBytes[:])
|
||||||
// Add k & v into the MT
|
// Add k & v into the MT
|
||||||
err = bb.mt.Add(idx.BigInt(), v)
|
err = bb.mt.Add(idx.BigInt(), v)
|
||||||
@@ -73,10 +73,10 @@ func (bb *BatchBuilder) UpdateBalance(tx db.Tx, idx common.Idx, amount *big.Int,
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// store the Leaf value
|
// store the Account value
|
||||||
tx.Put(v.Bytes(), leafBytes[:])
|
tx.Put(v.Bytes(), leafBytes[:])
|
||||||
// Add k & v into the MT
|
// Add k & v into the MT
|
||||||
err = bb.mt.Update(idx.BigInt(), v)
|
_, err = bb.mt.Update(idx.BigInt(), v)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,18 +1,133 @@
|
|||||||
package common
|
package common
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"bytes"
|
||||||
|
"encoding/binary"
|
||||||
|
"fmt"
|
||||||
"math/big"
|
"math/big"
|
||||||
|
|
||||||
eth "github.com/ethereum/go-ethereum/common"
|
eth "github.com/ethereum/go-ethereum/common"
|
||||||
"github.com/iden3/go-iden3-crypto/babyjub"
|
"github.com/iden3/go-iden3-crypto/babyjub"
|
||||||
|
"github.com/iden3/go-iden3-crypto/poseidon"
|
||||||
|
cryptoUtils "github.com/iden3/go-iden3-crypto/utils"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Account is a struct that gives information of the holdings of an address for a specific token
|
const NLEAFELEMS = 4
|
||||||
|
|
||||||
|
// Account is a struct that gives information of the holdings of an address for a specific token. Is the data structure that generates the Value stored in the leaf of the MerkleTree
|
||||||
type Account struct {
|
type Account struct {
|
||||||
|
TokenID TokenID
|
||||||
|
Nonce uint64 // max of 40 bits used
|
||||||
|
Balance *big.Int // max of 192 bits used
|
||||||
|
PublicKey *babyjub.PublicKey
|
||||||
EthAddr eth.Address
|
EthAddr eth.Address
|
||||||
TokenID TokenID // effective 32 bits
|
}
|
||||||
Idx uint32 // bits = SMT levels (SMT levels needs to be decided)
|
|
||||||
Nonce uint64 // effective 48 bits
|
// Bytes returns the bytes representing the Account, 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.
|
||||||
Balance *big.Int // Up to 192 bits
|
func (l *Account) Bytes() ([32 * NLEAFELEMS]byte, error) {
|
||||||
PublicKey babyjub.PublicKey
|
var b [32 * NLEAFELEMS]byte
|
||||||
|
|
||||||
|
if l.Nonce > 0xffffffffff {
|
||||||
|
return b, fmt.Errorf("%s Nonce", ErrNumOverflow)
|
||||||
|
}
|
||||||
|
if len(l.Balance.Bytes()) > 24 {
|
||||||
|
return b, fmt.Errorf("%s Balance", ErrNumOverflow)
|
||||||
|
}
|
||||||
|
|
||||||
|
var tokenIDBytes [4]byte
|
||||||
|
binary.LittleEndian.PutUint32(tokenIDBytes[:], uint32(l.TokenID))
|
||||||
|
var nonceBytes [8]byte
|
||||||
|
binary.LittleEndian.PutUint64(nonceBytes[:], l.Nonce)
|
||||||
|
|
||||||
|
copy(b[0:4], tokenIDBytes[:])
|
||||||
|
copy(b[4:9], nonceBytes[:])
|
||||||
|
if babyjub.PointCoordSign(l.PublicKey.X) {
|
||||||
|
b[10] = 1
|
||||||
|
}
|
||||||
|
copy(b[32:64], SwapEndianness(l.Balance.Bytes())) // SwapEndianness, as big.Int uses BigEndian
|
||||||
|
copy(b[64:96], SwapEndianness(l.PublicKey.Y.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 *Account) BigInts() ([NLEAFELEMS]*big.Int, error) {
|
||||||
|
e := [NLEAFELEMS]*big.Int{}
|
||||||
|
|
||||||
|
b, err := l.Bytes()
|
||||||
|
if err != nil {
|
||||||
|
return e, err
|
||||||
|
}
|
||||||
|
|
||||||
|
e[0] = new(big.Int).SetBytes(SwapEndianness(b[0:32]))
|
||||||
|
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]))
|
||||||
|
|
||||||
|
return e, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// HashValue returns the value of the Account, which is the Poseidon hash of its *big.Int representation
|
||||||
|
func (l *Account) HashValue() (*big.Int, error) {
|
||||||
|
b0 := big.NewInt(0)
|
||||||
|
toHash := [poseidon.T]*big.Int{b0, b0, b0, b0, b0, b0}
|
||||||
|
lBI, err := l.BigInts()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
copy(toHash[:], lBI[:])
|
||||||
|
|
||||||
|
v, err := poseidon.Hash(toHash)
|
||||||
|
return v, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// AccountFromBigInts returns a Account from a [5]*big.Int
|
||||||
|
func AccountFromBigInts(e [NLEAFELEMS]*big.Int) (*Account, error) {
|
||||||
|
if !cryptoUtils.CheckBigIntArrayInField(e[:]) {
|
||||||
|
return nil, ErrNotInFF
|
||||||
|
}
|
||||||
|
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()))
|
||||||
|
|
||||||
|
return AccountFromBytes(b)
|
||||||
|
}
|
||||||
|
|
||||||
|
// AccountFromBytes returns a Account from a byte array
|
||||||
|
func AccountFromBytes(b [32 * NLEAFELEMS]byte) (*Account, error) {
|
||||||
|
tokenID := binary.LittleEndian.Uint32(b[0:4])
|
||||||
|
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)
|
||||||
|
}
|
||||||
|
ay := new(big.Int).SetBytes(SwapEndianness(b[64:96]))
|
||||||
|
pkPoint, err := babyjub.PointFromSignAndY(sign, ay)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
publicKey := babyjub.PublicKey(*pkPoint)
|
||||||
|
ethAddr := eth.BytesToAddress(b[96:116])
|
||||||
|
|
||||||
|
if !cryptoUtils.CheckBigIntInField(balance) {
|
||||||
|
return nil, ErrNotInFF
|
||||||
|
}
|
||||||
|
if !cryptoUtils.CheckBigIntInField(ay) {
|
||||||
|
return nil, ErrNotInFF
|
||||||
|
}
|
||||||
|
|
||||||
|
l := Account{
|
||||||
|
TokenID: TokenID(tokenID),
|
||||||
|
Nonce: nonce,
|
||||||
|
Balance: balance,
|
||||||
|
PublicKey: &publicKey,
|
||||||
|
EthAddr: ethAddr,
|
||||||
|
}
|
||||||
|
return &l, nil
|
||||||
}
|
}
|
||||||
|
|||||||
196
common/account_test.go
Normal file
196
common/account_test.go
Normal file
@@ -0,0 +1,196 @@
|
|||||||
|
package common
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/hex"
|
||||||
|
"fmt"
|
||||||
|
"math"
|
||||||
|
"math/big"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
ethCommon "github.com/ethereum/go-ethereum/common"
|
||||||
|
ethCrypto "github.com/ethereum/go-ethereum/crypto"
|
||||||
|
"github.com/iden3/go-iden3-crypto/babyjub"
|
||||||
|
cryptoConstants "github.com/iden3/go-iden3-crypto/constants"
|
||||||
|
cryptoUtils "github.com/iden3/go-iden3-crypto/utils"
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestAccount(t *testing.T) {
|
||||||
|
var sk babyjub.PrivateKey
|
||||||
|
_, err := hex.Decode(sk[:], []byte("0001020304050607080900010203040506070809000102030405060708090001"))
|
||||||
|
assert.Nil(t, err)
|
||||||
|
pk := sk.Public()
|
||||||
|
|
||||||
|
account := &Account{
|
||||||
|
TokenID: TokenID(1),
|
||||||
|
Nonce: uint64(1234),
|
||||||
|
Balance: big.NewInt(1000),
|
||||||
|
PublicKey: pk,
|
||||||
|
EthAddr: ethCommon.HexToAddress("0xc58d29fA6e86E4FAe04DDcEd660d45BCf3Cb2370"),
|
||||||
|
}
|
||||||
|
b, err := account.Bytes()
|
||||||
|
assert.Nil(t, err)
|
||||||
|
assert.Equal(t, byte(1), b[10])
|
||||||
|
a1, err := AccountFromBytes(b)
|
||||||
|
assert.Nil(t, err)
|
||||||
|
assert.Equal(t, account, a1)
|
||||||
|
|
||||||
|
e, err := account.BigInts()
|
||||||
|
assert.Nil(t, err)
|
||||||
|
assert.True(t, cryptoUtils.CheckBigIntInField(e[0]))
|
||||||
|
assert.True(t, cryptoUtils.CheckBigIntInField(e[1]))
|
||||||
|
assert.True(t, cryptoUtils.CheckBigIntInField(e[2]))
|
||||||
|
assert.True(t, cryptoUtils.CheckBigIntInField(e[3]))
|
||||||
|
|
||||||
|
assert.Equal(t, "1000", e[1].String())
|
||||||
|
assert.Equal(t, pk.Y.String(), e[2].String())
|
||||||
|
assert.Equal(t, new(big.Int).SetBytes(SwapEndianness(account.EthAddr.Bytes())).String(), e[3].String())
|
||||||
|
|
||||||
|
a2, err := AccountFromBigInts(e)
|
||||||
|
assert.Nil(t, err)
|
||||||
|
assert.Equal(t, account, a2)
|
||||||
|
assert.Equal(t, a1, a2)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestAccountLoop(t *testing.T) {
|
||||||
|
// check that for different Address there is no problem
|
||||||
|
for i := 0; i < 256; i++ {
|
||||||
|
var sk babyjub.PrivateKey
|
||||||
|
_, err := hex.Decode(sk[:], []byte("0001020304050607080900010203040506070809000102030405060708090001"))
|
||||||
|
assert.Nil(t, err)
|
||||||
|
pk := sk.Public()
|
||||||
|
|
||||||
|
key, err := ethCrypto.GenerateKey()
|
||||||
|
assert.Nil(t, err)
|
||||||
|
address := ethCrypto.PubkeyToAddress(key.PublicKey)
|
||||||
|
|
||||||
|
account := &Account{
|
||||||
|
TokenID: TokenID(i),
|
||||||
|
Nonce: uint64(i),
|
||||||
|
Balance: big.NewInt(1000),
|
||||||
|
PublicKey: pk,
|
||||||
|
EthAddr: address,
|
||||||
|
}
|
||||||
|
b, err := account.Bytes()
|
||||||
|
assert.Nil(t, err)
|
||||||
|
a1, err := AccountFromBytes(b)
|
||||||
|
assert.Nil(t, err)
|
||||||
|
assert.Equal(t, account, a1)
|
||||||
|
|
||||||
|
e, err := account.BigInts()
|
||||||
|
assert.Nil(t, err)
|
||||||
|
assert.True(t, cryptoUtils.CheckBigIntInField(e[0]))
|
||||||
|
assert.True(t, cryptoUtils.CheckBigIntInField(e[1]))
|
||||||
|
assert.True(t, cryptoUtils.CheckBigIntInField(e[2]))
|
||||||
|
assert.True(t, cryptoUtils.CheckBigIntInField(e[3]))
|
||||||
|
|
||||||
|
a2, err := AccountFromBigInts(e)
|
||||||
|
assert.Nil(t, err)
|
||||||
|
assert.Equal(t, account, a2)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestAccountHashValue(t *testing.T) {
|
||||||
|
var sk babyjub.PrivateKey
|
||||||
|
_, err := hex.Decode(sk[:], []byte("0001020304050607080900010203040506070809000102030405060708090001"))
|
||||||
|
assert.Nil(t, err)
|
||||||
|
pk := sk.Public()
|
||||||
|
|
||||||
|
account := &Account{
|
||||||
|
TokenID: TokenID(1),
|
||||||
|
Nonce: uint64(1234),
|
||||||
|
Balance: big.NewInt(1000),
|
||||||
|
PublicKey: pk,
|
||||||
|
EthAddr: ethCommon.HexToAddress("0xc58d29fA6e86E4FAe04DDcEd660d45BCf3Cb2370"),
|
||||||
|
}
|
||||||
|
|
||||||
|
v, err := account.HashValue()
|
||||||
|
assert.Nil(t, err)
|
||||||
|
assert.Equal(t, "6335844662301214382338419199835935731871537354006112711277201708185593574314", v.String())
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestAccountErrNotInFF(t *testing.T) {
|
||||||
|
z := big.NewInt(0)
|
||||||
|
|
||||||
|
// Q-1 should not give error
|
||||||
|
r := new(big.Int).Sub(cryptoConstants.Q, big.NewInt(1))
|
||||||
|
e := [NLEAFELEMS]*big.Int{z, z, r, r}
|
||||||
|
_, err := AccountFromBigInts(e)
|
||||||
|
assert.Nil(t, err)
|
||||||
|
|
||||||
|
// Q should give error
|
||||||
|
r = cryptoConstants.Q
|
||||||
|
e = [NLEAFELEMS]*big.Int{z, z, r, r}
|
||||||
|
_, err = AccountFromBigInts(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 = [NLEAFELEMS]*big.Int{z, z, r, r}
|
||||||
|
_, err = AccountFromBigInts(e)
|
||||||
|
assert.NotNil(t, err)
|
||||||
|
assert.Equal(t, ErrNotInFF, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestAccountErrNumOverflowNonce(t *testing.T) {
|
||||||
|
var sk babyjub.PrivateKey
|
||||||
|
_, err := hex.Decode(sk[:], []byte("0001020304050607080900010203040506070809000102030405060708090001"))
|
||||||
|
assert.Nil(t, err)
|
||||||
|
pk := sk.Public()
|
||||||
|
|
||||||
|
// check limit
|
||||||
|
account := &Account{
|
||||||
|
TokenID: TokenID(1),
|
||||||
|
Nonce: uint64(math.Pow(2, 40) - 1),
|
||||||
|
Balance: big.NewInt(1000),
|
||||||
|
PublicKey: pk,
|
||||||
|
EthAddr: ethCommon.HexToAddress("0xc58d29fA6e86E4FAe04DDcEd660d45BCf3Cb2370"),
|
||||||
|
}
|
||||||
|
_, err = account.Bytes()
|
||||||
|
assert.Nil(t, err)
|
||||||
|
|
||||||
|
// force value overflow
|
||||||
|
account.Nonce = uint64(math.Pow(2, 40))
|
||||||
|
b, err := account.Bytes()
|
||||||
|
assert.NotNil(t, err)
|
||||||
|
assert.Equal(t, fmt.Errorf("%s Nonce", ErrNumOverflow), err)
|
||||||
|
|
||||||
|
_, err = AccountFromBytes(b)
|
||||||
|
assert.Nil(t, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestAccountErrNumOverflowBalance(t *testing.T) {
|
||||||
|
var sk babyjub.PrivateKey
|
||||||
|
_, err := hex.Decode(sk[:], []byte("0001020304050607080900010203040506070809000102030405060708090001"))
|
||||||
|
assert.Nil(t, err)
|
||||||
|
pk := sk.Public()
|
||||||
|
|
||||||
|
// check limit
|
||||||
|
account := &Account{
|
||||||
|
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)),
|
||||||
|
PublicKey: pk,
|
||||||
|
EthAddr: ethCommon.HexToAddress("0xc58d29fA6e86E4FAe04DDcEd660d45BCf3Cb2370"),
|
||||||
|
}
|
||||||
|
assert.Equal(t, "6277101735386680763835789423207666416102355444464034512895", account.Balance.String())
|
||||||
|
|
||||||
|
_, err = account.Bytes()
|
||||||
|
assert.Nil(t, err)
|
||||||
|
|
||||||
|
// force value overflow
|
||||||
|
account.Balance = new(big.Int).Exp(big.NewInt(2), big.NewInt(192), nil)
|
||||||
|
assert.Equal(t, "6277101735386680763835789423207666416102355444464034512896", account.Balance.String())
|
||||||
|
b, err := account.Bytes()
|
||||||
|
assert.NotNil(t, err)
|
||||||
|
assert.Equal(t, fmt.Errorf("%s Balance", ErrNumOverflow), err)
|
||||||
|
|
||||||
|
_, err = AccountFromBytes(b)
|
||||||
|
assert.Nil(t, err)
|
||||||
|
|
||||||
|
b[56] = 1
|
||||||
|
_, err = AccountFromBytes(b)
|
||||||
|
assert.NotNil(t, err)
|
||||||
|
assert.Equal(t, fmt.Errorf("%s Balance", ErrNumOverflow), err)
|
||||||
|
}
|
||||||
128
common/leaf.go
128
common/leaf.go
@@ -1,128 +0,0 @@
|
|||||||
package common
|
|
||||||
|
|
||||||
import (
|
|
||||||
"bytes"
|
|
||||||
"encoding/binary"
|
|
||||||
"fmt"
|
|
||||||
"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
|
|
||||||
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 * NLEAFELEMS]byte, error) {
|
|
||||||
var b [32 * NLEAFELEMS]byte
|
|
||||||
|
|
||||||
if l.Nonce > 0xffffffffff {
|
|
||||||
return b, fmt.Errorf("%s Nonce", ErrNumOverflow)
|
|
||||||
}
|
|
||||||
if len(l.Balance.Bytes()) > 24 {
|
|
||||||
return b, fmt.Errorf("%s Balance", ErrNumOverflow)
|
|
||||||
}
|
|
||||||
|
|
||||||
var tokenIDBytes [4]byte
|
|
||||||
binary.LittleEndian.PutUint32(tokenIDBytes[:], uint32(l.TokenID))
|
|
||||||
var nonceBytes [8]byte
|
|
||||||
binary.LittleEndian.PutUint64(nonceBytes[:], l.Nonce)
|
|
||||||
|
|
||||||
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.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() ([NLEAFELEMS]*big.Int, error) {
|
|
||||||
e := [NLEAFELEMS]*big.Int{}
|
|
||||||
|
|
||||||
b, err := l.Bytes()
|
|
||||||
if err != nil {
|
|
||||||
return e, err
|
|
||||||
}
|
|
||||||
|
|
||||||
e[0] = new(big.Int).SetBytes(SwapEndianness(b[0:32]))
|
|
||||||
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]))
|
|
||||||
|
|
||||||
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 [NLEAFELEMS]*big.Int) (*Leaf, error) {
|
|
||||||
if !cryptoUtils.CheckBigIntArrayInField(e[:]) {
|
|
||||||
return nil, ErrNotInFF
|
|
||||||
}
|
|
||||||
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()))
|
|
||||||
|
|
||||||
return LeafFromBytes(b)
|
|
||||||
}
|
|
||||||
|
|
||||||
// LeafFromBytes returns a Leaf from a byte array
|
|
||||||
func LeafFromBytes(b [32 * NLEAFELEMS]byte) (*Leaf, error) {
|
|
||||||
tokenID := binary.LittleEndian.Uint32(b[0:4])
|
|
||||||
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)
|
|
||||||
}
|
|
||||||
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(ay) {
|
|
||||||
return nil, ErrNotInFF
|
|
||||||
}
|
|
||||||
|
|
||||||
l := Leaf{
|
|
||||||
TokenID: TokenID(tokenID),
|
|
||||||
Nonce: nonce,
|
|
||||||
Balance: balance,
|
|
||||||
Sign: sign,
|
|
||||||
Ay: ay,
|
|
||||||
EthAddr: ethAddr,
|
|
||||||
}
|
|
||||||
return &l, nil
|
|
||||||
}
|
|
||||||
@@ -1,158 +0,0 @@
|
|||||||
package common
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"math"
|
|
||||||
"math/big"
|
|
||||||
"testing"
|
|
||||||
|
|
||||||
ethCommon "github.com/ethereum/go-ethereum/common"
|
|
||||||
cryptoConstants "github.com/iden3/go-iden3-crypto/constants"
|
|
||||||
cryptoUtils "github.com/iden3/go-iden3-crypto/utils"
|
|
||||||
"github.com/stretchr/testify/assert"
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestLeaf(t *testing.T) {
|
|
||||||
leaf := &Leaf{
|
|
||||||
TokenID: TokenID(1),
|
|
||||||
Nonce: uint64(1234),
|
|
||||||
Balance: big.NewInt(1000),
|
|
||||||
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)
|
|
||||||
|
|
||||||
e, err := leaf.BigInts()
|
|
||||||
assert.Nil(t, err)
|
|
||||||
assert.True(t, cryptoUtils.CheckBigIntInField(e[0]))
|
|
||||||
assert.True(t, cryptoUtils.CheckBigIntInField(e[1]))
|
|
||||||
assert.True(t, cryptoUtils.CheckBigIntInField(e[2]))
|
|
||||||
assert.True(t, cryptoUtils.CheckBigIntInField(e[3]))
|
|
||||||
|
|
||||||
assert.Equal(t, "1000", e[1].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)
|
|
||||||
assert.Equal(t, leaf, l2)
|
|
||||||
assert.Equal(t, l1, l2)
|
|
||||||
}
|
|
||||||
|
|
||||||
// func TestLeafLoop(t *testing.T) {
|
|
||||||
// // check that for different Address there is no problem
|
|
||||||
// for i := 0; i < 256; i++ {
|
|
||||||
// key, err := ethCrypto.GenerateKey()
|
|
||||||
// assert.Nil(t, err)
|
|
||||||
// address := ethCrypto.PubkeyToAddress(key.PublicKey)
|
|
||||||
//
|
|
||||||
// leaf := &Leaf{
|
|
||||||
// TokenID: TokenID(i),
|
|
||||||
// Nonce: uint64(i),
|
|
||||||
// Balance: big.NewInt(1000),
|
|
||||||
// Sign: true,
|
|
||||||
// Ay: big.NewInt(6789),
|
|
||||||
// EthAddr: address,
|
|
||||||
// }
|
|
||||||
// b, err := leaf.Bytes()
|
|
||||||
// assert.Nil(t, err)
|
|
||||||
// l1, err := LeafFromBytes(b)
|
|
||||||
// assert.Nil(t, err)
|
|
||||||
// assert.Equal(t, leaf, l1)
|
|
||||||
//
|
|
||||||
// e, err := leaf.BigInts()
|
|
||||||
// assert.Nil(t, err)
|
|
||||||
// assert.True(t, cryptoUtils.CheckBigIntInField(e[0]))
|
|
||||||
// assert.True(t, cryptoUtils.CheckBigIntInField(e[1]))
|
|
||||||
// assert.True(t, cryptoUtils.CheckBigIntInField(e[2]))
|
|
||||||
// assert.True(t, cryptoUtils.CheckBigIntInField(e[3]))
|
|
||||||
//
|
|
||||||
// l2, err := LeafFromBigInts(e)
|
|
||||||
// assert.Nil(t, err)
|
|
||||||
// assert.Equal(t, leaf, l2)
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
func TestLeafErrNotInFF(t *testing.T) {
|
|
||||||
z := big.NewInt(0)
|
|
||||||
|
|
||||||
// Q-1 should not give error
|
|
||||||
r := new(big.Int).Sub(cryptoConstants.Q, big.NewInt(1))
|
|
||||||
e := [NLEAFELEMS]*big.Int{z, z, r, r}
|
|
||||||
_, err := LeafFromBigInts(e)
|
|
||||||
assert.Nil(t, err)
|
|
||||||
|
|
||||||
// Q should give error
|
|
||||||
r = cryptoConstants.Q
|
|
||||||
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 = [NLEAFELEMS]*big.Int{z, z, r, r}
|
|
||||||
_, err = LeafFromBigInts(e)
|
|
||||||
assert.NotNil(t, err)
|
|
||||||
assert.Equal(t, ErrNotInFF, err)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestLeafErrNumOverflowNonce(t *testing.T) {
|
|
||||||
// check limit
|
|
||||||
leaf := &Leaf{
|
|
||||||
TokenID: TokenID(1),
|
|
||||||
Nonce: uint64(math.Pow(2, 40) - 1),
|
|
||||||
Balance: big.NewInt(1000),
|
|
||||||
Sign: true,
|
|
||||||
Ay: big.NewInt(6789),
|
|
||||||
EthAddr: ethCommon.HexToAddress("0xc58d29fA6e86E4FAe04DDcEd660d45BCf3Cb2370"),
|
|
||||||
}
|
|
||||||
_, err := leaf.Bytes()
|
|
||||||
assert.Nil(t, err)
|
|
||||||
|
|
||||||
// force value overflow
|
|
||||||
leaf.Nonce = uint64(math.Pow(2, 40))
|
|
||||||
b, err := leaf.Bytes()
|
|
||||||
assert.NotNil(t, err)
|
|
||||||
assert.Equal(t, fmt.Errorf("%s Nonce", ErrNumOverflow), err)
|
|
||||||
|
|
||||||
_, err = LeafFromBytes(b)
|
|
||||||
assert.Nil(t, err)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestLeafErrNumOverflowBalance(t *testing.T) {
|
|
||||||
// check limit
|
|
||||||
leaf := &Leaf{
|
|
||||||
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)),
|
|
||||||
Sign: true,
|
|
||||||
Ay: big.NewInt(6789),
|
|
||||||
EthAddr: ethCommon.HexToAddress("0xc58d29fA6e86E4FAe04DDcEd660d45BCf3Cb2370"),
|
|
||||||
}
|
|
||||||
assert.Equal(t, "6277101735386680763835789423207666416102355444464034512895", leaf.Balance.String())
|
|
||||||
|
|
||||||
_, err := leaf.Bytes()
|
|
||||||
assert.Nil(t, err)
|
|
||||||
|
|
||||||
// force value overflow
|
|
||||||
leaf.Balance = new(big.Int).Exp(big.NewInt(2), big.NewInt(192), nil)
|
|
||||||
assert.Equal(t, "6277101735386680763835789423207666416102355444464034512896", leaf.Balance.String())
|
|
||||||
b, err := leaf.Bytes()
|
|
||||||
assert.NotNil(t, err)
|
|
||||||
assert.Equal(t, fmt.Errorf("%s Balance", ErrNumOverflow), err)
|
|
||||||
|
|
||||||
_, err = LeafFromBytes(b)
|
|
||||||
assert.Nil(t, err)
|
|
||||||
|
|
||||||
b[56] = 1
|
|
||||||
_, err = LeafFromBytes(b)
|
|
||||||
assert.NotNil(t, err)
|
|
||||||
assert.Equal(t, fmt.Errorf("%s Balance", ErrNumOverflow), err)
|
|
||||||
}
|
|
||||||
215
db/statedb/statedb.go
Normal file
215
db/statedb/statedb.go
Normal file
@@ -0,0 +1,215 @@
|
|||||||
|
package statedb
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
|
||||||
|
"github.com/hermeznetwork/hermez-node/common"
|
||||||
|
"github.com/iden3/go-merkletree"
|
||||||
|
"github.com/iden3/go-merkletree/db"
|
||||||
|
"github.com/iden3/go-merkletree/db/leveldb"
|
||||||
|
"github.com/iden3/go-merkletree/db/memory"
|
||||||
|
)
|
||||||
|
|
||||||
|
// ErrStateDBWithoutMT is used when a method that requires a MerkleTree is called in a StateDB that does not have a MerkleTree defined
|
||||||
|
var ErrStateDBWithoutMT = errors.New("Can not call method to use MerkleTree in a StateDB without MerkleTree")
|
||||||
|
|
||||||
|
// ErrAccountAlreadyExists is used when CreateAccount is called and the Account already exists
|
||||||
|
var ErrAccountAlreadyExists = errors.New("Can not CreateAccount because Account already exists")
|
||||||
|
|
||||||
|
// StateDB represents the StateDB object
|
||||||
|
type StateDB struct {
|
||||||
|
db db.Storage
|
||||||
|
mt *merkletree.MerkleTree
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewStateDB creates a new StateDB, allowing to use an in-memory or in-disk
|
||||||
|
// storage
|
||||||
|
func NewStateDB(path string, inDisk bool, withMT bool, nLevels int) (*StateDB, error) {
|
||||||
|
var sto db.Storage
|
||||||
|
var err error
|
||||||
|
if inDisk {
|
||||||
|
sto, err = leveldb.NewLevelDbStorage(path, false)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
sto = memory.NewMemoryStorage()
|
||||||
|
}
|
||||||
|
var mt *merkletree.MerkleTree = nil
|
||||||
|
if withMT {
|
||||||
|
mt, err = merkletree.NewMerkleTree(sto, nLevels)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return &StateDB{
|
||||||
|
db: sto,
|
||||||
|
mt: mt,
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// CheckPointAt does a checkpoint at the given batchNum in the defined path
|
||||||
|
func (s *StateDB) CheckPointAt(batchNum int, path string) error {
|
||||||
|
// TODO
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Reset resets the StateDB to the checkpoint at the given batchNum
|
||||||
|
func (s *StateDB) Reset(batchNum int) error {
|
||||||
|
// TODO
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Checkpoints returns a list of the checkpoints (batchNums)
|
||||||
|
func (s *StateDB) Checkpoints() ([]int, error) {
|
||||||
|
// TODO
|
||||||
|
|
||||||
|
//batchnums, err
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetAccount returns the account for the given Idx
|
||||||
|
func (s *StateDB) GetAccount(idx common.Idx) (*common.Account, error) {
|
||||||
|
vBytes, err := s.db.Get(idx.Bytes())
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
accBytes, err := s.db.Get(vBytes)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
var b [32 * common.NLEAFELEMS]byte
|
||||||
|
copy(b[:], accBytes)
|
||||||
|
return common.AccountFromBytes(b)
|
||||||
|
}
|
||||||
|
|
||||||
|
// CreateAccount creates a new Account in the StateDB for the given Idx.
|
||||||
|
// MerkleTree is not affected.
|
||||||
|
func (s *StateDB) CreateAccount(idx common.Idx, account *common.Account) error {
|
||||||
|
// store at the DB the key: v, and value: leaf.Bytes()
|
||||||
|
v, err := account.HashValue()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
accountBytes, err := account.Bytes()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// store the Leaf value
|
||||||
|
tx, err := s.db.NewTx()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err = tx.Get(idx.Bytes())
|
||||||
|
if err != db.ErrNotFound {
|
||||||
|
return ErrAccountAlreadyExists
|
||||||
|
}
|
||||||
|
|
||||||
|
tx.Put(v.Bytes(), accountBytes[:])
|
||||||
|
tx.Put(idx.Bytes(), v.Bytes())
|
||||||
|
|
||||||
|
return tx.Commit()
|
||||||
|
}
|
||||||
|
|
||||||
|
// UpdateAccount updates the Account in the StateDB for the given Idx.
|
||||||
|
// MerkleTree is not affected.
|
||||||
|
func (s *StateDB) UpdateAccount(idx common.Idx, account *common.Account) error {
|
||||||
|
// store at the DB the key: v, and value: leaf.Bytes()
|
||||||
|
v, err := account.HashValue()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
accountBytes, err := account.Bytes()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
tx, err := s.db.NewTx()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
tx.Put(v.Bytes(), accountBytes[:])
|
||||||
|
tx.Put(idx.Bytes(), v.Bytes())
|
||||||
|
|
||||||
|
return tx.Commit()
|
||||||
|
}
|
||||||
|
|
||||||
|
// MTCreateAccount creates a new the Account in the StateDB for the given Idx,
|
||||||
|
// and updates the MerkleTree, returning a CircomProcessorProof
|
||||||
|
func (s *StateDB) MTCreateAccount(idx common.Idx, account *common.Account) (*merkletree.CircomProcessorProof, error) {
|
||||||
|
if s.mt == nil {
|
||||||
|
return nil, ErrStateDBWithoutMT
|
||||||
|
}
|
||||||
|
err := s.CreateAccount(idx, account)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
v, err := account.HashValue() // already computed in s.CreateAccount, next iteration reuse first computation
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
// Add k & v into the MT
|
||||||
|
return s.mt.AddAndGetCircomProof(idx.BigInt(), v)
|
||||||
|
}
|
||||||
|
|
||||||
|
// MTUpdateAccount updates the Account in the StateDB for the given Idx, and
|
||||||
|
// updates the MerkleTree, returning a CircomProcessorProof
|
||||||
|
func (s *StateDB) MTUpdateAccount(idx common.Idx, account *common.Account) (*merkletree.CircomProcessorProof, error) {
|
||||||
|
if s.mt == nil {
|
||||||
|
return nil, ErrStateDBWithoutMT
|
||||||
|
}
|
||||||
|
err := s.UpdateAccount(idx, account)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
v, err := account.HashValue() // already computed in s.CreateAccount, next iteration reuse first computation
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
// Add k & v into the MT
|
||||||
|
return s.mt.Update(idx.BigInt(), v)
|
||||||
|
}
|
||||||
|
|
||||||
|
// MTGetProof returns the CircomVerifierProof for a given Idx
|
||||||
|
func (s *StateDB) MTGetProof(idx common.Idx) (*merkletree.CircomVerifierProof, error) {
|
||||||
|
if s.mt == nil {
|
||||||
|
return nil, ErrStateDBWithoutMT
|
||||||
|
}
|
||||||
|
return s.mt.GenerateCircomVerifierProof(idx.BigInt(), s.mt.Root())
|
||||||
|
}
|
||||||
|
|
||||||
|
// LocalStateDB represents the local StateDB which allows to make copies from
|
||||||
|
// the synchronizer StateDB, and is used by the tx-selector and the
|
||||||
|
// batch-builder. LocalStateDB is an in-memory storage.
|
||||||
|
type LocalStateDB struct {
|
||||||
|
*StateDB
|
||||||
|
synchronizerStateDB *StateDB
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewLocalStateDB returns a new LocalStateDB connected to the given
|
||||||
|
// synchronizerDB
|
||||||
|
func NewLocalStateDB(synchronizerDB *StateDB, withMT bool, nLevels int) (*LocalStateDB, error) {
|
||||||
|
s, err := NewStateDB("", false, withMT, nLevels)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return &LocalStateDB{
|
||||||
|
s,
|
||||||
|
synchronizerDB,
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Reset performs a reset, getting the state from
|
||||||
|
// LocalStateDB.synchronizerStateDB for the given batchNum
|
||||||
|
func (l *LocalStateDB) Reset(batchNum int, fromSynchronizer bool) error {
|
||||||
|
// TODO
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
144
db/statedb/statedb_test.go
Normal file
144
db/statedb/statedb_test.go
Normal file
@@ -0,0 +1,144 @@
|
|||||||
|
package statedb
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/hex"
|
||||||
|
"io/ioutil"
|
||||||
|
"math/big"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
ethCrypto "github.com/ethereum/go-ethereum/crypto"
|
||||||
|
"github.com/hermeznetwork/hermez-node/common"
|
||||||
|
"github.com/iden3/go-iden3-crypto/babyjub"
|
||||||
|
"github.com/iden3/go-merkletree/db"
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
"github.com/stretchr/testify/require"
|
||||||
|
)
|
||||||
|
|
||||||
|
func newAccount(t *testing.T, i int) *common.Account {
|
||||||
|
var sk babyjub.PrivateKey
|
||||||
|
_, err := hex.Decode(sk[:], []byte("0001020304050607080900010203040506070809000102030405060708090001"))
|
||||||
|
require.Nil(t, err)
|
||||||
|
pk := sk.Public()
|
||||||
|
|
||||||
|
key, err := ethCrypto.GenerateKey()
|
||||||
|
require.Nil(t, err)
|
||||||
|
address := ethCrypto.PubkeyToAddress(key.PublicKey)
|
||||||
|
|
||||||
|
return &common.Account{
|
||||||
|
TokenID: common.TokenID(i),
|
||||||
|
Nonce: uint64(i),
|
||||||
|
Balance: big.NewInt(1000),
|
||||||
|
PublicKey: pk,
|
||||||
|
EthAddr: address,
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestStateDBWithoutMT(t *testing.T) {
|
||||||
|
dir, err := ioutil.TempDir("", "tmpdb")
|
||||||
|
require.Nil(t, err)
|
||||||
|
|
||||||
|
sdb, err := NewStateDB(dir, false, false, 0)
|
||||||
|
assert.Nil(t, err)
|
||||||
|
|
||||||
|
// create test accounts
|
||||||
|
var accounts []*common.Account
|
||||||
|
for i := 0; i < 100; i++ {
|
||||||
|
accounts = append(accounts, newAccount(t, i))
|
||||||
|
}
|
||||||
|
|
||||||
|
// get non-existing account, expecting an error
|
||||||
|
_, err = sdb.GetAccount(common.Idx(1))
|
||||||
|
assert.NotNil(t, err)
|
||||||
|
assert.Equal(t, db.ErrNotFound, err)
|
||||||
|
|
||||||
|
// add test accounts
|
||||||
|
for i := 0; i < len(accounts); i++ {
|
||||||
|
err = sdb.CreateAccount(common.Idx(i), accounts[i])
|
||||||
|
assert.Nil(t, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
for i := 0; i < len(accounts); i++ {
|
||||||
|
accGetted, err := sdb.GetAccount(common.Idx(i))
|
||||||
|
assert.Nil(t, err)
|
||||||
|
assert.Equal(t, accounts[i], accGetted)
|
||||||
|
}
|
||||||
|
|
||||||
|
// try already existing idx and get error
|
||||||
|
_, err = sdb.GetAccount(common.Idx(1)) // check that exist
|
||||||
|
assert.Nil(t, err)
|
||||||
|
err = sdb.CreateAccount(common.Idx(1), accounts[1]) // check that can not be created twice
|
||||||
|
assert.NotNil(t, err)
|
||||||
|
assert.Equal(t, ErrAccountAlreadyExists, err)
|
||||||
|
|
||||||
|
// update accounts
|
||||||
|
for i := 0; i < len(accounts); i++ {
|
||||||
|
accounts[i].Nonce = accounts[i].Nonce + 1
|
||||||
|
err = sdb.UpdateAccount(common.Idx(i), accounts[i])
|
||||||
|
assert.Nil(t, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// check that can not call MerkleTree methods of the StateDB
|
||||||
|
_, err = sdb.MTCreateAccount(common.Idx(1), accounts[1])
|
||||||
|
assert.NotNil(t, err)
|
||||||
|
assert.Equal(t, ErrStateDBWithoutMT, err)
|
||||||
|
|
||||||
|
_, err = sdb.MTUpdateAccount(common.Idx(1), accounts[1])
|
||||||
|
assert.NotNil(t, err)
|
||||||
|
assert.Equal(t, ErrStateDBWithoutMT, err)
|
||||||
|
|
||||||
|
_, err = sdb.MTGetProof(common.Idx(1))
|
||||||
|
assert.NotNil(t, err)
|
||||||
|
assert.Equal(t, ErrStateDBWithoutMT, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestStateDBWithMT(t *testing.T) {
|
||||||
|
dir, err := ioutil.TempDir("", "tmpdb")
|
||||||
|
require.Nil(t, err)
|
||||||
|
|
||||||
|
sdb, err := NewStateDB(dir, false, true, 32)
|
||||||
|
assert.Nil(t, err)
|
||||||
|
|
||||||
|
// create test accounts
|
||||||
|
var accounts []*common.Account
|
||||||
|
for i := 0; i < 100; i++ {
|
||||||
|
accounts = append(accounts, newAccount(t, i))
|
||||||
|
}
|
||||||
|
|
||||||
|
// get non-existing account, expecting an error
|
||||||
|
_, err = sdb.GetAccount(common.Idx(1))
|
||||||
|
assert.NotNil(t, err)
|
||||||
|
assert.Equal(t, db.ErrNotFound, err)
|
||||||
|
|
||||||
|
// add test accounts
|
||||||
|
for i := 0; i < len(accounts); i++ {
|
||||||
|
_, err = sdb.MTCreateAccount(common.Idx(i), accounts[i])
|
||||||
|
assert.Nil(t, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
for i := 0; i < len(accounts); i++ {
|
||||||
|
accGetted, err := sdb.GetAccount(common.Idx(i))
|
||||||
|
assert.Nil(t, err)
|
||||||
|
assert.Equal(t, accounts[i], accGetted)
|
||||||
|
}
|
||||||
|
|
||||||
|
// try already existing idx and get error
|
||||||
|
_, err = sdb.GetAccount(common.Idx(1)) // check that exist
|
||||||
|
assert.Nil(t, err)
|
||||||
|
_, err = sdb.MTCreateAccount(common.Idx(1), accounts[1]) // check that can not be created twice
|
||||||
|
assert.NotNil(t, err)
|
||||||
|
assert.Equal(t, ErrAccountAlreadyExists, err)
|
||||||
|
|
||||||
|
_, err = sdb.MTGetProof(common.Idx(1))
|
||||||
|
assert.Nil(t, err)
|
||||||
|
|
||||||
|
// update accounts
|
||||||
|
for i := 0; i < len(accounts); i++ {
|
||||||
|
accounts[i].Nonce = accounts[i].Nonce + 1
|
||||||
|
_, err = sdb.MTUpdateAccount(common.Idx(i), accounts[i])
|
||||||
|
assert.Nil(t, err)
|
||||||
|
}
|
||||||
|
a, err := sdb.GetAccount(common.Idx(1)) // check that account value has been updated
|
||||||
|
assert.Nil(t, err)
|
||||||
|
assert.Equal(t, accounts[1].Nonce, a.Nonce)
|
||||||
|
}
|
||||||
4
go.mod
4
go.mod
@@ -5,8 +5,8 @@ go 1.14
|
|||||||
require (
|
require (
|
||||||
github.com/dghubble/sling v1.3.0
|
github.com/dghubble/sling v1.3.0
|
||||||
github.com/ethereum/go-ethereum v1.9.17
|
github.com/ethereum/go-ethereum v1.9.17
|
||||||
github.com/iden3/go-iden3-crypto v0.0.6-0.20200723082457-29a66457f0bf
|
github.com/iden3/go-iden3-crypto v0.0.6-0.20200806115047-327a8175d6eb
|
||||||
github.com/iden3/go-merkletree v0.0.0-20200723202738-75e24244a1e3
|
github.com/iden3/go-merkletree v0.0.0-20200807083900-f6f82d8375d5
|
||||||
github.com/jinzhu/gorm v1.9.15
|
github.com/jinzhu/gorm v1.9.15
|
||||||
github.com/stretchr/testify v1.6.1
|
github.com/stretchr/testify v1.6.1
|
||||||
)
|
)
|
||||||
|
|||||||
9
go.sum
9
go.sum
@@ -109,6 +109,7 @@ github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5y
|
|||||||
github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||||
github.com/golang/protobuf v1.3.2-0.20190517061210-b285ee9cfc6c/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
github.com/golang/protobuf v1.3.2-0.20190517061210-b285ee9cfc6c/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||||
github.com/golang/snappy v0.0.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
|
github.com/golang/snappy v0.0.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
|
||||||
|
github.com/golang/snappy v0.0.2-0.20200707131729-196ae77b8a26 h1:lMm2hD9Fy0ynom5+85/pbdkiYcBqM1JWmhpAXLmy0fw=
|
||||||
github.com/golang/snappy v0.0.2-0.20200707131729-196ae77b8a26/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
|
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.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
|
||||||
github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
|
github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
|
||||||
@@ -135,8 +136,14 @@ github.com/iden3/go-iden3-crypto v0.0.5 h1:inCSm5a+ry+nbpVTL/9+m6UcIwSv6nhUm0tnI
|
|||||||
github.com/iden3/go-iden3-crypto v0.0.5/go.mod h1:XKw1oDwYn2CIxKOtr7m/mL5jMn4mLOxAxtZBRxQBev8=
|
github.com/iden3/go-iden3-crypto v0.0.5/go.mod h1:XKw1oDwYn2CIxKOtr7m/mL5jMn4mLOxAxtZBRxQBev8=
|
||||||
github.com/iden3/go-iden3-crypto v0.0.6-0.20200723082457-29a66457f0bf h1:/7L5dEqctuzJY2g8OEQct+1Y+n2sMKyd4JoYhw2jy1s=
|
github.com/iden3/go-iden3-crypto v0.0.6-0.20200723082457-29a66457f0bf h1:/7L5dEqctuzJY2g8OEQct+1Y+n2sMKyd4JoYhw2jy1s=
|
||||||
github.com/iden3/go-iden3-crypto v0.0.6-0.20200723082457-29a66457f0bf/go.mod h1:XKw1oDwYn2CIxKOtr7m/mL5jMn4mLOxAxtZBRxQBev8=
|
github.com/iden3/go-iden3-crypto v0.0.6-0.20200723082457-29a66457f0bf/go.mod h1:XKw1oDwYn2CIxKOtr7m/mL5jMn4mLOxAxtZBRxQBev8=
|
||||||
|
github.com/iden3/go-iden3-crypto v0.0.6-0.20200806115047-327a8175d6eb h1:4Vqq5ZoqQd9t3Uj7MUbak7eHmtaYs8mqQoo8T1DS7tA=
|
||||||
|
github.com/iden3/go-iden3-crypto v0.0.6-0.20200806115047-327a8175d6eb/go.mod h1:XKw1oDwYn2CIxKOtr7m/mL5jMn4mLOxAxtZBRxQBev8=
|
||||||
github.com/iden3/go-merkletree v0.0.0-20200723202738-75e24244a1e3 h1:QR6LqG1HqqPE4myiLR73QFIieAfwODG3bqo1juuaqVI=
|
github.com/iden3/go-merkletree v0.0.0-20200723202738-75e24244a1e3 h1:QR6LqG1HqqPE4myiLR73QFIieAfwODG3bqo1juuaqVI=
|
||||||
github.com/iden3/go-merkletree v0.0.0-20200723202738-75e24244a1e3/go.mod h1:Fc49UeywIsj8nUfb5lxBzmWrMeMmqzTJ5F0OcjdiEME=
|
github.com/iden3/go-merkletree v0.0.0-20200723202738-75e24244a1e3/go.mod h1:Fc49UeywIsj8nUfb5lxBzmWrMeMmqzTJ5F0OcjdiEME=
|
||||||
|
github.com/iden3/go-merkletree v0.0.0-20200806171216-dd600560e44c h1:EzVMSVkwKdfcOR1a+rZe9dfbtAj6KdJnBxOEZ5B+gCQ=
|
||||||
|
github.com/iden3/go-merkletree v0.0.0-20200806171216-dd600560e44c/go.mod h1:Fc49UeywIsj8nUfb5lxBzmWrMeMmqzTJ5F0OcjdiEME=
|
||||||
|
github.com/iden3/go-merkletree v0.0.0-20200807083900-f6f82d8375d5 h1:qvWSCt3AYxj65uTdW6lLSKlrbckcHghOAW4TwdfJ+N8=
|
||||||
|
github.com/iden3/go-merkletree v0.0.0-20200807083900-f6f82d8375d5/go.mod h1:Fc49UeywIsj8nUfb5lxBzmWrMeMmqzTJ5F0OcjdiEME=
|
||||||
github.com/iden3/go-wasm3 v0.0.1/go.mod h1:j+TcAB94Dfrjlu5kJt83h2OqAU+oyNUTwNZnQyII1sI=
|
github.com/iden3/go-wasm3 v0.0.1/go.mod h1:j+TcAB94Dfrjlu5kJt83h2OqAU+oyNUTwNZnQyII1sI=
|
||||||
github.com/influxdata/influxdb v1.2.3-0.20180221223340-01288bdb0883/go.mod h1:qZna6X/4elxqT3yI9iZYdZrWWdeFOOprn86kgg4+IzY=
|
github.com/influxdata/influxdb v1.2.3-0.20180221223340-01288bdb0883/go.mod h1:qZna6X/4elxqT3yI9iZYdZrWWdeFOOprn86kgg4+IzY=
|
||||||
github.com/influxdata/influxdb v1.7.8/go.mod h1:qZna6X/4elxqT3yI9iZYdZrWWdeFOOprn86kgg4+IzY=
|
github.com/influxdata/influxdb v1.7.8/go.mod h1:qZna6X/4elxqT3yI9iZYdZrWWdeFOOprn86kgg4+IzY=
|
||||||
@@ -225,6 +232,7 @@ github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAm
|
|||||||
github.com/shirou/gopsutil v2.20.5+incompatible/go.mod h1:5b4v6he4MtMOwMlS0TUMTu2PcXUg8+E1lC7eC3UO/RA=
|
github.com/shirou/gopsutil v2.20.5+incompatible/go.mod h1:5b4v6he4MtMOwMlS0TUMTu2PcXUg8+E1lC7eC3UO/RA=
|
||||||
github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc=
|
github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc=
|
||||||
github.com/siddontang/go v0.0.0-20180604090527-bdc77568d726/go.mod h1:3yhqj7WBBfRhbBlzyOC3gUxftwsU0u8gqevxwIHQpMw=
|
github.com/siddontang/go v0.0.0-20180604090527-bdc77568d726/go.mod h1:3yhqj7WBBfRhbBlzyOC3gUxftwsU0u8gqevxwIHQpMw=
|
||||||
|
github.com/sirupsen/logrus v1.5.0 h1:1N5EYkVAPEywqZRJd7cwnRtCb6xJx7NH3T3WUTF980Q=
|
||||||
github.com/sirupsen/logrus v1.5.0/go.mod h1:+F7Ogzej0PZc/94MaYx/nvG9jOFMD2osvC3s+Squfpo=
|
github.com/sirupsen/logrus v1.5.0/go.mod h1:+F7Ogzej0PZc/94MaYx/nvG9jOFMD2osvC3s+Squfpo=
|
||||||
github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=
|
github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=
|
||||||
github.com/spaolacci/murmur3 v1.0.1-0.20190317074736-539464a789e9/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=
|
github.com/spaolacci/murmur3 v1.0.1-0.20190317074736-539464a789e9/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=
|
||||||
@@ -241,6 +249,7 @@ github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81P
|
|||||||
github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
|
github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
|
||||||
github.com/stretchr/testify v1.6.1 h1:hDPOHmpOpP40lSULcqw7IrRb/u7w6RpDC9399XyoNd0=
|
github.com/stretchr/testify v1.6.1 h1:hDPOHmpOpP40lSULcqw7IrRb/u7w6RpDC9399XyoNd0=
|
||||||
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||||
|
github.com/syndtr/goleveldb v1.0.1-0.20190923125748-758128399b1d h1:gZZadD8H+fF+n9CmNhYL1Y0dJB+kLOmKd7FbPJLeGHs=
|
||||||
github.com/syndtr/goleveldb v1.0.1-0.20190923125748-758128399b1d/go.mod h1:9OrXJhf154huy1nPWmuSrkgjPUtUNhA+Zmy+6AESzuA=
|
github.com/syndtr/goleveldb v1.0.1-0.20190923125748-758128399b1d/go.mod h1:9OrXJhf154huy1nPWmuSrkgjPUtUNhA+Zmy+6AESzuA=
|
||||||
github.com/tyler-smith/go-bip39 v1.0.1-0.20181017060643-dbb3b84ba2ef/go.mod h1:sJ5fKU0s6JVwZjjcUEX2zFOnvq0ASQ2K9Zr6cf67kNs=
|
github.com/tyler-smith/go-bip39 v1.0.1-0.20181017060643-dbb3b84ba2ef/go.mod h1:sJ5fKU0s6JVwZjjcUEX2zFOnvq0ASQ2K9Zr6cf67kNs=
|
||||||
github.com/tyler-smith/go-bip39 v1.0.2/go.mod h1:sJ5fKU0s6JVwZjjcUEX2zFOnvq0ASQ2K9Zr6cf67kNs=
|
github.com/tyler-smith/go-bip39 v1.0.2/go.mod h1:sJ5fKU0s6JVwZjjcUEX2zFOnvq0ASQ2K9Zr6cf67kNs=
|
||||||
|
|||||||
Reference in New Issue
Block a user