arnaucube
arnaucube/hermez-nodePublic Self-hosted repository
Add GeneratePoolL2Txs for a parsed set
arnaucube root@arnaucube.com
Wed, 07 Oct 2020 16:20:29 +0200
commit

182e3d36f5d71b97f8d1fae463332c1710426920

parent

06ae1897d81689582d1c9bdf79bc7f4e5c15fb13

3 files changed, 164 insertions(+), 63 deletions(-)

jump to
M test/lang.go → test/lang.go

@@ -45,9 +45,9 @@ TokenID common.TokenID

Type common.TxType // D: Deposit, T: Transfer, E: ForceExit } -// Instructions contains the full Set of Instructions representing a full code -type Instructions struct { - Instructions []*Instruction +// ParsedSet contains the full Set of Instructions representing a full code +type ParsedSet struct { + Instructions []Instruction Accounts []string TokenIDs []common.TokenID }

@@ -389,8 +389,8 @@ return idx + strconv.Itoa(int(tid))

} // Parse parses through reader -func (p *Parser) Parse() (Instructions, error) { - var instructions Instructions +func (p *Parser) Parse() (*ParsedSet, error) { + instructions := &ParsedSet{} i := 0 accounts := make(map[string]bool) tokenids := make(map[common.TokenID]bool)

@@ -405,13 +405,13 @@ continue

} if err == newEvent { i++ - instructions.Instructions = append(instructions.Instructions, instruction) + instructions.Instructions = append(instructions.Instructions, *instruction) continue } if err != nil { return instructions, fmt.Errorf("error parsing line %d: %s, err: %s", i, instruction.Literal, err.Error()) } - instructions.Instructions = append(instructions.Instructions, instruction) + instructions.Instructions = append(instructions.Instructions, *instruction) accounts[idxTokenIDToString(instruction.From, instruction.TokenID)] = true if instruction.Type == common.TxTypeTransfer { // type: Transfer accounts[idxTokenIDToString(instruction.To, instruction.TokenID)] = true
M test/txs.go → test/txs.go

@@ -6,14 +6,33 @@ "math/big"

"strconv" "strings" "testing" + "time" ethCommon "github.com/ethereum/go-ethereum/common" ethCrypto "github.com/ethereum/go-ethereum/crypto" "github.com/hermeznetwork/hermez-node/common" + "github.com/hermeznetwork/hermez-node/log" "github.com/iden3/go-iden3-crypto/babyjub" "github.com/stretchr/testify/require" ) +type TestContext struct { + t *testing.T + Instructions []Instruction + accountsNames []string + accounts map[string]*Account + TokenIDs []common.TokenID + l1CreatedAccounts map[string]*Account +} + +func NewTestContext(t *testing.T) *TestContext { + return &TestContext{ + t: t, + accounts: make(map[string]*Account), + l1CreatedAccounts: make(map[string]*Account), + } +} + // Account contains the data related to a testing account type Account struct { BJJ *babyjub.PrivateKey

@@ -22,12 +41,105 @@ Idx common.Idx

Nonce common.Nonce } -// GenerateKeys generates BabyJubJub & Address keys for the given list of +// func (tc *TestContext) GenerateBlocks() []BlockData { +// +// return nil +// } + +// GeneratePoolL2Txs returns an array of common.PoolL2Tx from a given set. It +// uses the accounts (keys & nonces) of the TestContext. +func (tc *TestContext) GeneratePoolL2Txs(set string) []common.PoolL2Tx { + parser := NewParser(strings.NewReader(set)) + parsedSet, err := parser.Parse() + require.Nil(tc.t, err) + + tc.Instructions = parsedSet.Instructions + tc.accountsNames = parsedSet.Accounts + tc.TokenIDs = parsedSet.TokenIDs + + tc.generateKeys(tc.accountsNames) + + txs := []common.PoolL2Tx{} + for _, inst := range tc.Instructions { + switch inst.Type { + case common.TxTypeTransfer: + tc.accounts[idxTokenIDToString(inst.From, inst.TokenID)].Nonce++ + // if account of receiver does not exist, don't use + // ToIdx, and use only ToEthAddr & ToBJJ + toIdx := new(common.Idx) + if _, ok := tc.l1CreatedAccounts[idxTokenIDToString(inst.To, inst.TokenID)]; !ok { + *toIdx = 0 + } else { + *toIdx = tc.accounts[idxTokenIDToString(inst.To, inst.TokenID)].Idx + } + // TODO once common.L{x}Txs parameter pointers is undone, update this lines related to pointers usage + toEthAddr := new(ethCommon.Address) + *toEthAddr = tc.accounts[idxTokenIDToString(inst.To, inst.TokenID)].Addr + rqToEthAddr := new(ethCommon.Address) + *rqToEthAddr = tc.accounts[idxTokenIDToString(inst.To, inst.TokenID)].Addr + tx := common.PoolL2Tx{ + FromIdx: tc.accounts[idxTokenIDToString(inst.From, inst.TokenID)].Idx, + ToIdx: toIdx, + ToEthAddr: toEthAddr, + ToBJJ: tc.accounts[idxTokenIDToString(inst.To, inst.TokenID)].BJJ.Public(), + TokenID: inst.TokenID, + Amount: big.NewInt(int64(inst.Amount)), + Fee: common.FeeSelector(inst.Fee), + Nonce: tc.accounts[idxTokenIDToString(inst.From, inst.TokenID)].Nonce, + State: common.PoolL2TxStatePending, + Timestamp: time.Now(), + BatchNum: nil, + RqToEthAddr: rqToEthAddr, + RqToBJJ: tc.accounts[idxTokenIDToString(inst.To, inst.TokenID)].BJJ.Public(), + Type: common.TxTypeTransfer, + } + nTx, err := common.NewPoolL2Tx(&tx) + if err != nil { + panic(err) + } + tx = *nTx + // perform signature and set it to tx.Signature + toSign, err := tx.HashToSign() + if err != nil { + panic(err) + } + sig := tc.accounts[idxTokenIDToString(inst.To, inst.TokenID)].BJJ.SignPoseidon(toSign) + tx.Signature = sig + + txs = append(txs, tx) + case common.TxTypeExit: + tc.accounts[idxTokenIDToString(inst.From, inst.TokenID)].Nonce++ + // TODO once common.L{x}Txs parameter pointers is undone, update this lines related to pointers usage + toIdx := new(common.Idx) + *toIdx = common.Idx(1) // as is an Exit + tx := common.PoolL2Tx{ + FromIdx: tc.accounts[idxTokenIDToString(inst.From, inst.TokenID)].Idx, + ToIdx: toIdx, // as is an Exit + TokenID: inst.TokenID, + Amount: big.NewInt(int64(inst.Amount)), + Nonce: tc.accounts[idxTokenIDToString(inst.From, inst.TokenID)].Nonce, + Type: common.TxTypeExit, + } + txs = append(txs, tx) + default: + log.Warnf("instruction type unrecognized: %s", inst.Type) + continue + } + } + + return txs +} + +// generateKeys generates BabyJubJub & Address keys for the given list of // account names in a deterministic way. This means, that for the same given -// 'accNames' the keys will be always the same. -func GenerateKeys(t *testing.T, accNames []string) map[string]*Account { +// 'accNames' in a certain order, the keys will be always the same. +func (tc *TestContext) generateKeys(accNames []string) map[string]*Account { acc := make(map[string]*Account) for i := 1; i < len(accNames)+1; i++ { + if _, ok := tc.accounts[accNames[i-1]]; ok { + // account already created + continue + } // babyjubjub key var sk babyjub.PrivateKey copy(sk[:], []byte(strconv.Itoa(i))) // only for testing

@@ -44,15 +156,16 @@ BJJ: &sk,

Addr: addr, Nonce: 0, } - acc[accNames[i-1]] = &a + tc.accounts[accNames[i-1]] = &a } return acc } +/* // GenerateTestTxs generates L1Tx & PoolL2Tx in a deterministic way for the -// given Instructions. -func GenerateTestTxs(t *testing.T, instructions Instructions) ([][]common.L1Tx, [][]common.L1Tx, [][]common.PoolL2Tx, []common.Token) { - accounts := GenerateKeys(t, instructions.Accounts) +// given ParsedSet. +func GenerateTestTxs(t *testing.T, parsedSet *ParsedSet) ([][]common.L1Tx, [][]common.L1Tx, [][]common.PoolL2Tx, []common.Token) { + accounts := generateKeys(t, parsedSet.Accounts) l1CreatedAccounts := make(map[string]*Account) var batchL1Txs []common.L1Tx

@@ -62,7 +175,7 @@ var l1Txs [][]common.L1Tx

var coordinatorL1Txs [][]common.L1Tx var poolL2Txs [][]common.PoolL2Tx idx := 256 - for _, inst := range instructions.Instructions { + for _, inst := range parsedSet.Instructions { switch inst.Type { case common.TxTypeCreateAccountDeposit: tx := common.L1Tx{

@@ -176,8 +289,9 @@ // GenerateTestTxsFromSet reurns the L1 & L2 transactions for a given Set of

// Instructions code func GenerateTestTxsFromSet(t *testing.T, set string) ([][]common.L1Tx, [][]common.L1Tx, [][]common.PoolL2Tx, []common.Token) { parser := NewParser(strings.NewReader(set)) - instructions, err := parser.Parse() + parsedSet, err := parser.Parse() require.Nil(t, err) - return GenerateTestTxs(t, instructions) + return GenerateTestTxs(t, parsedSet) } +*/
M test/txs_test.go → test/txs_test.go

@@ -1,59 +1,46 @@

package test import ( - "strings" "testing" "github.com/hermeznetwork/hermez-node/common" "github.com/stretchr/testify/assert" ) -func TestGenerateTestL2Txs(t *testing.T) { - s := ` - A (1): 10 - A (2): 20 - B (1): 5 - A-B (1): 6 1 - B-C (1): 3 1 - > advance batch - C-A (1): 3 1 - A-B (1): 1 1 - A-B (2): 15 1 - User0 (1): 20 - User1 (3) : 20 - User0-User1 (1): 15 1 - User1-User0 (3): 15 1 - B-D (2): 3 1 +func TestGeneratePoolL2Txs(t *testing.T) { + set := ` + Transfer(1) A-B: 6 (1) + Transfer(1) B-C: 3 (1) + Transfer(1) C-A: 3 (1) + Transfer(1) A-B: 1 (1) + Transfer(2) A-B: 15 (1) + Transfer(1) User0-User1: 15 (1) + Transfer(3) User1-User0: 15 (1) + Transfer(2) B-D: 3 (1) + Exit(1) A: 3 ` - parser := NewParser(strings.NewReader(s)) - instructions, err := parser.Parse() - assert.Nil(t, err) + tc := NewTestContext(t) + poolL2Txs := tc.GeneratePoolL2Txs(set) + assert.Equal(t, 9, len(poolL2Txs)) + assert.Equal(t, common.TxTypeTransfer, poolL2Txs[0].Type) + assert.Equal(t, common.TxTypeExit, poolL2Txs[8].Type) + assert.Equal(t, tc.accounts["B1"].Addr.Hex(), poolL2Txs[0].ToEthAddr.Hex()) + assert.Equal(t, tc.accounts["B1"].BJJ.Public().String(), poolL2Txs[0].ToBJJ.String()) + assert.Equal(t, tc.accounts["User11"].Addr.Hex(), poolL2Txs[5].ToEthAddr.Hex()) + assert.Equal(t, tc.accounts["User11"].BJJ.Public().String(), poolL2Txs[5].ToBJJ.String()) - l1txs, coordinatorL1txs, l2txs, _ := GenerateTestTxs(t, instructions) - assert.Equal(t, 2, len(l1txs)) - assert.Equal(t, 3, len(l1txs[0])) - assert.Equal(t, 1, len(coordinatorL1txs[0])) - assert.Equal(t, 2, len(l2txs[0])) - assert.Equal(t, 2, len(l1txs[1])) - assert.Equal(t, 4, len(coordinatorL1txs[1])) - assert.Equal(t, 6, len(l2txs[1])) + assert.Equal(t, common.Nonce(1), poolL2Txs[0].Nonce) + assert.Equal(t, common.Nonce(2), poolL2Txs[3].Nonce) + assert.Equal(t, common.Nonce(3), poolL2Txs[8].Nonce) - accounts := GenerateKeys(t, instructions.Accounts) - - // l1txs - assert.Equal(t, common.TxTypeCreateAccountDeposit, l1txs[0][0].Type) - assert.Equal(t, accounts["A1"].BJJ.Public().String(), l1txs[0][0].FromBJJ.String()) - assert.Equal(t, accounts["A2"].BJJ.Public().String(), l1txs[0][1].FromBJJ.String()) - assert.Equal(t, accounts["B1"].BJJ.Public().String(), l1txs[0][2].FromBJJ.String()) - assert.Equal(t, accounts["User13"].BJJ.Public().String(), l1txs[1][1].FromBJJ.String()) - - // l2txs - assert.Equal(t, common.TxTypeTransfer, l2txs[0][0].Type) - assert.Equal(t, common.Idx(256), l2txs[0][0].FromIdx) - assert.Equal(t, common.Idx(258), l2txs[0][0].ToIdx) - assert.Equal(t, accounts["B1"].BJJ.Public().String(), l2txs[0][0].ToBJJ.String()) - assert.Equal(t, accounts["B1"].Addr.Hex(), l2txs[0][0].ToEthAddr.Hex()) - assert.Equal(t, common.Nonce(0), l2txs[0][0].Nonce) - assert.Equal(t, common.Nonce(1), l2txs[1][1].Nonce) - assert.Equal(t, common.FeeSelector(1), l2txs[0][0].Fee) + // load another set in the same TestContext + set = ` + Transfer(1) A-B: 6 (1) + Transfer(1) B-C: 3 (1) + Transfer(1) A-C: 3 (1) + ` + poolL2Txs = tc.GeneratePoolL2Txs(set) + assert.Equal(t, common.Nonce(4), poolL2Txs[0].Nonce) + assert.Equal(t, common.Nonce(2), poolL2Txs[1].Nonce) + assert.Equal(t, common.Nonce(5), poolL2Txs[2].Nonce) }