arnaucube
arnaucube/hermez-nodePublic Self-hosted repository
hermez-node/test/txs.go
test/txs.goRaw
  1package test
  2
  3import (
  4	"crypto/ecdsa"
  5	"math/big"
  6	"strconv"
  7	"strings"
  8	"testing"
  9	"time"
 10
 11	ethCommon "github.com/ethereum/go-ethereum/common"
 12	ethCrypto "github.com/ethereum/go-ethereum/crypto"
 13	"github.com/hermeznetwork/hermez-node/common"
 14	"github.com/iden3/go-iden3-crypto/babyjub"
 15	"github.com/stretchr/testify/require"
 16)
 17
 18type Account struct {
 19	BJJ   *babyjub.PrivateKey
 20	Addr  ethCommon.Address
 21	Idx   common.Idx
 22	Nonce common.Nonce
 23}
 24
 25// GenerateKeys generates BabyJubJub & Address keys for the given list of
 26// account names in a deterministic way. This means, that for the same given
 27// 'accNames' the keys will be always the same.
 28func GenerateKeys(t *testing.T, accNames []string) map[string]*Account {
 29	acc := make(map[string]*Account)
 30	for i := 1; i < len(accNames)+1; i++ {
 31		// babyjubjub key
 32		var sk babyjub.PrivateKey
 33		copy(sk[:], []byte(strconv.Itoa(i))) // only for testing
 34
 35		// eth address
 36		var key ecdsa.PrivateKey
 37		key.D = big.NewInt(int64(i)) // only for testing
 38		key.PublicKey.X, key.PublicKey.Y = ethCrypto.S256().ScalarBaseMult(key.D.Bytes())
 39		key.Curve = ethCrypto.S256()
 40		addr := ethCrypto.PubkeyToAddress(key.PublicKey)
 41
 42		a := Account{
 43			BJJ:   &sk,
 44			Addr:  addr,
 45			Nonce: 0,
 46		}
 47		acc[accNames[i-1]] = &a
 48	}
 49	return acc
 50}
 51
 52// GenerateTestTxs generates L1Tx & PoolL2Tx in a deterministic way for the
 53// given Instructions.
 54func GenerateTestTxs(t *testing.T, instructions Instructions) ([][]*common.L1Tx, [][]*common.L1Tx, [][]*common.PoolL2Tx) {
 55	accounts := GenerateKeys(t, instructions.Accounts)
 56	l1CreatedAccounts := make(map[string]*Account)
 57
 58	var batchL1Txs []*common.L1Tx
 59	var batchCoordinatorL1Txs []*common.L1Tx
 60	var batchPoolL2Txs []*common.PoolL2Tx
 61	var l1Txs [][]*common.L1Tx
 62	var coordinatorL1Txs [][]*common.L1Tx
 63	var poolL2Txs [][]*common.PoolL2Tx
 64	idx := 1
 65	for _, inst := range instructions.Instructions {
 66		switch inst.Type {
 67		case common.TxTypeCreateAccountDeposit:
 68			tx := common.L1Tx{
 69				// TxID
 70				FromEthAddr: accounts[idxTokenIDToString(inst.From, inst.TokenID)].Addr,
 71				FromBJJ:     accounts[idxTokenIDToString(inst.From, inst.TokenID)].BJJ.Public(),
 72				TokenID:     inst.TokenID,
 73				LoadAmount:  big.NewInt(int64(inst.Amount)),
 74				Type:        common.TxTypeCreateAccountDeposit,
 75			}
 76			batchL1Txs = append(batchL1Txs, &tx)
 77			if accounts[idxTokenIDToString(inst.From, inst.TokenID)].Idx == common.Idx(0) { // if account.Idx is not set yet, set it and increment idx
 78				accounts[idxTokenIDToString(inst.From, inst.TokenID)].Idx = common.Idx(idx)
 79
 80				l1CreatedAccounts[idxTokenIDToString(inst.From, inst.TokenID)] = accounts[idxTokenIDToString(inst.From, inst.TokenID)]
 81				idx++
 82			}
 83		case common.TxTypeTransfer:
 84			// if account of receiver does not exist, create a new CoordinatorL1Tx creating the account
 85			if _, ok := l1CreatedAccounts[idxTokenIDToString(inst.To, inst.TokenID)]; !ok {
 86				tx := common.L1Tx{
 87					FromEthAddr: accounts[idxTokenIDToString(inst.To, inst.TokenID)].Addr,
 88					FromBJJ:     accounts[idxTokenIDToString(inst.To, inst.TokenID)].BJJ.Public(),
 89					TokenID:     inst.TokenID,
 90					LoadAmount:  big.NewInt(int64(inst.Amount)),
 91					Type:        common.TxTypeCreateAccountDeposit,
 92				}
 93				accounts[idxTokenIDToString(inst.To, inst.TokenID)].Idx = common.Idx(idx)
 94				l1CreatedAccounts[idxTokenIDToString(inst.To, inst.TokenID)] = accounts[idxTokenIDToString(inst.To, inst.TokenID)]
 95				batchCoordinatorL1Txs = append(batchCoordinatorL1Txs, &tx)
 96				idx++
 97			}
 98
 99			tx := common.PoolL2Tx{
100				// TxID: nil,
101				FromIdx:     accounts[idxTokenIDToString(inst.From, inst.TokenID)].Idx,
102				ToIdx:       accounts[idxTokenIDToString(inst.To, inst.TokenID)].Idx,
103				ToEthAddr:   accounts[idxTokenIDToString(inst.To, inst.TokenID)].Addr,
104				ToBJJ:       accounts[idxTokenIDToString(inst.To, inst.TokenID)].BJJ.Public(),
105				TokenID:     inst.TokenID,
106				Amount:      big.NewInt(int64(inst.Amount)),
107				Fee:         common.FeeSelector(inst.Fee),
108				Nonce:       accounts[idxTokenIDToString(inst.From, inst.TokenID)].Nonce,
109				State:       common.PoolL2TxStatePending,
110				Timestamp:   time.Now(),
111				BatchNum:    0,
112				RqToEthAddr: accounts[idxTokenIDToString(inst.To, inst.TokenID)].Addr,
113				RqToBJJ:     accounts[idxTokenIDToString(inst.To, inst.TokenID)].BJJ.Public(),
114				Type:        common.TxTypeTransfer,
115			}
116			// perform signature and set it to tx.Signature
117			toSign, err := tx.HashToSign()
118			if err != nil {
119				panic(err)
120			}
121			sig := accounts[idxTokenIDToString(inst.To, inst.TokenID)].BJJ.SignPoseidon(toSign)
122			tx.Signature = sig
123
124			accounts[idxTokenIDToString(inst.From, inst.TokenID)].Nonce++
125			batchPoolL2Txs = append(batchPoolL2Txs, &tx)
126
127		case common.TxTypeExit, common.TxTypeForceExit:
128			tx := common.L1Tx{
129				FromIdx: accounts[idxTokenIDToString(inst.From, inst.TokenID)].Idx,
130				ToIdx:   common.Idx(1), // as is an Exit
131				TokenID: inst.TokenID,
132				Amount:  big.NewInt(int64(inst.Amount)),
133				Type:    common.TxTypeExit,
134			}
135			batchL1Txs = append(batchL1Txs, &tx)
136		case TypeNewBatch:
137			l1Txs = append(l1Txs, batchL1Txs)
138			coordinatorL1Txs = append(coordinatorL1Txs, batchCoordinatorL1Txs)
139			poolL2Txs = append(poolL2Txs, batchPoolL2Txs)
140			batchL1Txs = []*common.L1Tx{}
141			batchCoordinatorL1Txs = []*common.L1Tx{}
142			batchPoolL2Txs = []*common.PoolL2Tx{}
143		default:
144			continue
145		}
146	}
147	l1Txs = append(l1Txs, batchL1Txs)
148	coordinatorL1Txs = append(coordinatorL1Txs, batchCoordinatorL1Txs)
149	poolL2Txs = append(poolL2Txs, batchPoolL2Txs)
150
151	return l1Txs, coordinatorL1Txs, poolL2Txs
152}
153
154func GenerateTestTxsFromSet(t *testing.T, set string) ([][]*common.L1Tx, [][]*common.L1Tx, [][]*common.PoolL2Tx) {
155	parser := NewParser(strings.NewReader(set))
156	instructions, err := parser.Parse()
157	require.Nil(t, err)
158
159	return GenerateTestTxs(t, instructions)
160}