diff --git a/batchbuilder/batchbuilder.go b/batchbuilder/batchbuilder.go new file mode 100644 index 0000000..26b4e41 --- /dev/null +++ b/batchbuilder/batchbuilder.go @@ -0,0 +1,161 @@ +package batchbuilder + +import ( + "math/big" + + ethCommon "github.com/ethereum/go-ethereum/common" + "github.com/hermeznetwork/hermez-node/common" + "github.com/iden3/go-merkletree" + "github.com/iden3/go-merkletree/db" + "github.com/iden3/go-merkletree/db/memory" +) + +type ConfigCircuit struct { + TxsMax uint64 + L1TxsMax uint64 + SMTLevelsMax uint64 +} + +type BatchBuilder struct { + StateDB db.Storage // where the MTs will be stored by the Synchronizer + idx uint64 + mt *merkletree.MerkleTree + configCircuits []ConfigCircuit +} + +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, + } + + bb.Reset(batchNum, idx, true) + + return &bb, nil +} + +// 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 { + + return nil +} + +func (bb *BatchBuilder) BuildBatch(configBatch ConfigBatch, l1usertxs, l1coordinatortxs []common.L1Tx, l2txs []common.L2Tx, tokenIDs []common.TokenID) (*common.ZKInputs, error) { + + for _, tx := range l1usertxs { + bb.processL1Tx(tx) + } + for _, tx := range l1coordinatortxs { + bb.processL1Tx(tx) + } + for _, tx := range l2txs { + switch tx.Type { + case common.TxTypeTransfer: + // go to the MT leaf of sender and receiver, and update + // balance & nonce + bb.applyTransfer(tx.Tx) + 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 + bb.applyTransfer(tx.Tx) + case common.TxTypeCreateAccountDeposit: + // add new leaf to the MT, update balance of the MT leaf + bb.applyCreateLeaf(tx) + case common.TxTypeDeposit: + // update balance of the MT leaf + bb.applyDeposit(tx) + case common.TxTypeDepositAndTransfer: + // update balance in MT leaf, update balance & nonce of sender + // & receiver + bb.applyDeposit(tx) // this after v0, can be done by bb.applyDepositAndTransfer in a single step + bb.applyTransfer(tx.Tx) + case common.TxTypeCreateAccountDepositAndTransfer: + // add new leaf to the merkletree, update balance in MT leaf, + // update balance & nonce of sender & receiver + bb.applyCreateLeaf(tx) + bb.applyTransfer(tx.Tx) + 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 { + k := big.NewInt(int64(bb.idx + 1)) + + leaf := common.Leaf{ + TokenID: tx.TokenID, + Nonce: 0, // TODO check always that a new leaf is created nonce is at 0 + Balance: tx.LoadAmount, + Ax: tx.FromBJJ.X, + Ay: tx.FromBJJ.Y, + EthAddr: tx.FromEthAddr, + } + + v, err := leaf.Value() + if err != nil { + return err + } + + // store at the DB the key: v, and value: leaf.Bytes() + dbTx, err := bb.mt.DB().NewTx() + if err != nil { + return err + } + leafBytes := leaf.Bytes() + dbTx.Put(v.Bytes(), leafBytes[:]) + + // Add k & v into the MT + err = bb.mt.Add(k, v) + if err != nil { + return err + } + + // if everything is fine, increment idx + bb.idx = bb.idx + 1 + return nil +} + +// applyDeposit updates the balance in the leaf of the depositer +func (bb *BatchBuilder) applyDeposit(tx common.L1Tx) error { + + 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 { + + return nil +} diff --git a/batchbuilder/batchbuilder_test.go b/batchbuilder/batchbuilder_test.go new file mode 100644 index 0000000..b8fd379 --- /dev/null +++ b/batchbuilder/batchbuilder_test.go @@ -0,0 +1,18 @@ +package batchbuilder + +import ( + "fmt" + "testing" + + "github.com/iden3/go-merkletree/db/memory" + "github.com/stretchr/testify/assert" +) + +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/common/leaf.go b/common/leaf.go index 9cb4e73..7bf60d6 100644 --- a/common/leaf.go +++ b/common/leaf.go @@ -8,6 +8,7 @@ import ( "math/big" eth "github.com/ethereum/go-ethereum/common" + "github.com/iden3/go-iden3-crypto/poseidon" cryptoUtils "github.com/iden3/go-iden3-crypto/utils" ) @@ -65,6 +66,16 @@ func (l *Leaf) BigInts() ([5]*big.Int, error) { return e, nil } +// Value returns the value of the Leaf, which is the Poseidon hash of its *big.Int representation +func (l *Leaf) Value() (*big.Int, error) { + toHash := [poseidon.T]*big.Int{} + lBI := l.BigInts() + 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) { if !cryptoUtils.CheckBigIntArrayInField(e[:]) { 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=