Feature/merge history l2 tables (#156)

* WIP rebase

* Combine both SQL DBs

* API and DB refactor
This commit is contained in:
a_bennassar
2020-09-29 18:27:07 +02:00
committed by GitHub
parent 8efbb7ab18
commit c6f70f3177
34 changed files with 1493 additions and 990 deletions

23
test/dbUtils.go Normal file
View File

@@ -0,0 +1,23 @@
package test
import (
"testing"
"github.com/stretchr/testify/assert"
)
// AssertUSD asserts pointers to float64, and checks that they are equal
// with a tolerance of 0.01%. After that, the actual value is setted to the expected value
// in order to be able to perform further assertions using the standar assert functions.
func AssertUSD(t *testing.T, expected, actual *float64) {
if actual == nil {
assert.Equal(t, expected, actual)
return
}
if *expected < *actual {
assert.InEpsilon(t, *actual, *expected, 0.0001)
} else if *expected > *actual {
assert.InEpsilon(t, *expected, *actual, 0.0001)
}
*expected = *actual
}

View File

@@ -3,6 +3,7 @@ package test
import (
"errors"
"fmt"
"math"
"math/big"
"strconv"
"time"
@@ -43,8 +44,10 @@ func GenTokens(nTokens int, blocks []common.Block) []common.Token {
EthAddr: ethCommon.BigToAddress(big.NewInt(int64(i))),
}
if i%2 == 0 {
token.USD = 3
token.USDUpdate = time.Now()
usd := 3.0
token.USD = &usd
now := time.Now()
token.USDUpdate = &now
}
tokens = append(tokens, token)
}
@@ -122,72 +125,118 @@ func GenL1Txs(
}
userTxs := []common.L1Tx{}
othersTxs := []common.L1Tx{}
_, nextTxsNum := GetNextToForgeNumAndBatch(batches)
for i := 0; i < totalTxs; i++ {
var tx common.L1Tx
if batches[i%len(batches)].ForgeL1TxsNum != 0 {
tx = common.L1Tx{
TxID: common.TxID(common.Hash([]byte("L1_" + strconv.Itoa(fromIdx+i)))),
ToForgeL1TxsNum: batches[i%len(batches)].ForgeL1TxsNum,
Position: i,
UserOrigin: i%2 == 0,
TokenID: tokens[i%len(tokens)].TokenID,
Amount: big.NewInt(int64(i + 1)),
LoadAmount: big.NewInt(int64(i + 1)),
EthBlockNum: blocks[i%len(blocks)].EthBlockNum,
Type: randomTxType(i),
}
if i%4 == 0 {
tx.BatchNum = batches[i%len(batches)].BatchNum
}
} else {
continue
token := tokens[i%len(tokens)]
var usd *float64
var lUSD *float64
amount := big.NewInt(int64(i + 1))
if token.USD != nil {
//nolint:gomnd
noDecimalsUSD := *token.USD / math.Pow(10, float64(token.Decimals))
f := new(big.Float).SetInt(amount)
af, _ := f.Float64()
usd = new(float64)
*usd = noDecimalsUSD * af
lUSD = new(float64)
*lUSD = noDecimalsUSD * af
}
if i < nUserTxs {
var from, to *common.Account
var err error
if i%2 == 0 {
from, err = randomAccount(i, true, userAddr, accounts)
if err != nil {
panic(err)
}
to, err = randomAccount(i, false, userAddr, accounts)
if err != nil {
panic(err)
}
} else {
from, err = randomAccount(i, false, userAddr, accounts)
if err != nil {
panic(err)
}
to, err = randomAccount(i, true, userAddr, accounts)
if err != nil {
panic(err)
}
}
tx.FromIdx = from.Idx
tx.FromEthAddr = from.EthAddr
tx.FromBJJ = from.PublicKey
tx.ToIdx = to.Idx
userTxs = append(userTxs, tx)
tx := common.L1Tx{
TxID: common.TxID(common.Hash([]byte("L1_" + strconv.Itoa(fromIdx+i)))),
Position: i,
UserOrigin: i%2 == 0,
TokenID: token.TokenID,
Amount: amount,
USD: usd,
LoadAmount: amount,
LoadAmountUSD: lUSD,
EthBlockNum: blocks[i%len(blocks)].EthBlockNum,
Type: randomTxType(i),
}
if batches[i%len(batches)].ForgeL1TxsNum != 0 {
// Add already forged txs
tx.BatchNum = &batches[i%len(batches)].BatchNum
setFromToAndAppend(tx, i, nUserTxs, userAddr, accounts, &userTxs, &othersTxs)
} else {
from, err := randomAccount(i, false, userAddr, accounts)
if err != nil {
panic(err)
}
to, err := randomAccount(i, false, userAddr, accounts)
if err != nil {
panic(err)
}
tx.FromIdx = from.Idx
tx.FromEthAddr = from.EthAddr
tx.FromBJJ = from.PublicKey
tx.ToIdx = to.Idx
othersTxs = append(othersTxs, tx)
// Add unforged txs
tx.ToForgeL1TxsNum = nextTxsNum
tx.UserOrigin = true
setFromToAndAppend(tx, i, nUserTxs, userAddr, accounts, &userTxs, &othersTxs)
}
}
return userTxs, othersTxs
}
// GetNextToForgeNumAndBatch returns the next BatchNum and ForgeL1TxsNum to be added
func GetNextToForgeNumAndBatch(batches []common.Batch) (common.BatchNum, int64) {
batchNum := batches[len(batches)-1].BatchNum + 1
var toForgeL1TxsNum int64
found := false
for i := len(batches) - 1; i >= 0; i-- {
if batches[i].ForgeL1TxsNum != 0 {
toForgeL1TxsNum = batches[i].ForgeL1TxsNum + 1
found = true
break
}
}
if !found {
panic("toForgeL1TxsNum not found")
}
return batchNum, toForgeL1TxsNum
}
func setFromToAndAppend(
tx common.L1Tx,
i, nUserTxs int,
userAddr *ethCommon.Address,
accounts []common.Account,
userTxs *[]common.L1Tx,
othersTxs *[]common.L1Tx,
) {
if i < nUserTxs {
var from, to *common.Account
var err error
if i%2 == 0 {
from, err = randomAccount(i, true, userAddr, accounts)
if err != nil {
panic(err)
}
to, err = randomAccount(i, false, userAddr, accounts)
if err != nil {
panic(err)
}
} else {
from, err = randomAccount(i, false, userAddr, accounts)
if err != nil {
panic(err)
}
to, err = randomAccount(i, true, userAddr, accounts)
if err != nil {
panic(err)
}
}
tx.FromIdx = from.Idx
tx.FromEthAddr = from.EthAddr
tx.FromBJJ = from.PublicKey
tx.ToIdx = to.Idx
*userTxs = append(*userTxs, tx)
} else {
from, err := randomAccount(i, false, userAddr, accounts)
if err != nil {
panic(err)
}
to, err := randomAccount(i, false, userAddr, accounts)
if err != nil {
panic(err)
}
tx.FromIdx = from.Idx
tx.FromEthAddr = from.EthAddr
tx.FromBJJ = from.PublicKey
tx.ToIdx = to.Idx
*othersTxs = append(*othersTxs, tx)
}
}
// GenL2Txs generates L2 txs. WARNING: This is meant for DB/API testing, and may not be fully consistent with the protocol.
func GenL2Txs(
fromIdx int,
@@ -204,14 +253,14 @@ func GenL2Txs(
userTxs := []common.L2Tx{}
othersTxs := []common.L2Tx{}
for i := 0; i < totalTxs; i++ {
amount := big.NewInt(int64(i + 1))
fee := common.FeeSelector(i % 256) //nolint:gomnd
tx := common.L2Tx{
TxID: common.TxID(common.Hash([]byte("L2_" + strconv.Itoa(fromIdx+i)))),
BatchNum: batches[i%len(batches)].BatchNum,
Position: i,
//nolint:gomnd
Amount: big.NewInt(int64(i + 1)),
//nolint:gomnd
Fee: common.FeeSelector(i % 256),
TxID: common.TxID(common.Hash([]byte("L2_" + strconv.Itoa(fromIdx+i)))),
BatchNum: batches[i%len(batches)].BatchNum,
Position: i,
Amount: amount,
Fee: fee,
Nonce: common.Nonce(i + 1),
EthBlockNum: blocks[i%len(blocks)].EthBlockNum,
Type: randomTxType(i),
@@ -240,7 +289,6 @@ func GenL2Txs(
}
tx.FromIdx = from.Idx
tx.ToIdx = to.Idx
userTxs = append(userTxs, tx)
} else {
from, err := randomAccount(i, false, userAddr, accounts)
if err != nil {
@@ -252,12 +300,55 @@ func GenL2Txs(
}
tx.FromIdx = from.Idx
tx.ToIdx = to.Idx
}
var usd *float64
var fUSD *float64
token := GetToken(tx.FromIdx, accounts, tokens)
if token.USD != nil {
//nolint:gomnd
noDecimalsUSD := *token.USD / math.Pow(10, float64(token.Decimals))
f := new(big.Float).SetInt(amount)
af, _ := f.Float64()
usd = new(float64)
fUSD = new(float64)
*usd = noDecimalsUSD * af
*fUSD = *usd * fee.Percentage()
}
tx.USD = usd
tx.FeeUSD = fUSD
if i < nUserTxs {
userTxs = append(userTxs, tx)
} else {
othersTxs = append(othersTxs, tx)
}
}
return userTxs, othersTxs
}
// GetToken returns the Token associated to an Idx given a list of tokens and accounts.
// It panics when not found, intended for testing only.
func GetToken(idx common.Idx, accs []common.Account, tokens []common.Token) common.Token {
var id common.TokenID
found := false
for _, acc := range accs {
if acc.Idx == idx {
found = true
id = acc.TokenID
break
}
}
if !found {
panic("tokenID not found")
}
for i := 0; i < len(tokens); i++ {
if tokens[i].TokenID == id {
return tokens[i]
}
}
panic("token not found")
}
// GenCoordinators generates coordinators. WARNING: This is meant for DB/API testing, and may not be fully consistent with the protocol.
func GenCoordinators(nCoords int, blocks []common.Block) []common.Coordinator {
coords := []common.Coordinator{}

View File

@@ -24,7 +24,7 @@ func CleanL2DB(db *sqlx.DB) {
// GenPoolTxs generates L2 pool txs.
// WARNING: This tx doesn't follow the protocol (signature, txID, ...)
// it's just to test getting/setting from/to the DB.
func GenPoolTxs(n int) []*common.PoolL2Tx {
func GenPoolTxs(n int, tokens []common.Token) []*common.PoolL2Tx {
txs := make([]*common.PoolL2Tx, 0, n)
privK := babyjub.NewRandPrivKey()
for i := 0; i < n; i++ {
@@ -44,21 +44,33 @@ func GenPoolTxs(n int) []*common.PoolL2Tx {
}
f := new(big.Float).SetInt(big.NewInt(int64(i)))
amountF, _ := f.Float64()
var usd, absFee *float64
fee := common.FeeSelector(i % 255) //nolint:gomnd
token := tokens[i%len(tokens)]
if token.USD != nil {
usd = new(float64)
absFee = new(float64)
*usd = *token.USD * amountF
*absFee = fee.Percentage() * *usd
}
tx := &common.PoolL2Tx{
TxID: common.TxID(common.Hash([]byte(strconv.Itoa(i)))),
FromIdx: common.Idx(i),
ToIdx: common.Idx(i + 1),
ToEthAddr: ethCommon.BigToAddress(big.NewInt(int64(i))),
ToBJJ: privK.Public(),
TokenID: common.TokenID(i),
Amount: big.NewInt(int64(i)),
AmountFloat: amountF,
//nolint:gomnd
Fee: common.FeeSelector(i % 255),
Nonce: common.Nonce(i),
State: state,
Signature: privK.SignPoseidon(big.NewInt(int64(i))),
Timestamp: time.Now().UTC(),
TxID: common.TxID(common.Hash([]byte(strconv.Itoa(i)))),
FromIdx: common.Idx(i),
ToIdx: common.Idx(i + 1),
ToEthAddr: ethCommon.BigToAddress(big.NewInt(int64(i))),
ToBJJ: privK.Public(),
TokenID: token.TokenID,
Amount: big.NewInt(int64(i)),
AmountFloat: amountF,
USD: usd,
Fee: fee,
Nonce: common.Nonce(i),
State: state,
Signature: privK.SignPoseidon(big.NewInt(int64(i))),
Timestamp: time.Now().UTC(),
TokenSymbol: token.Symbol,
AbsoluteFee: absFee,
AbsoluteFeeUpdate: token.USDUpdate,
}
if i%2 == 0 { // Optional parameters: rq
tx.RqFromIdx = common.Idx(i)
@@ -72,8 +84,6 @@ func GenPoolTxs(n int) []*common.PoolL2Tx {
}
if i%3 == 0 { // Optional parameters: things that get updated "a posteriori"
tx.BatchNum = 489
tx.AbsoluteFee = 39.12345
tx.AbsoluteFeeUpdate = time.Now().UTC()
}
txs = append(txs, tx)
}

View File

@@ -52,7 +52,7 @@ func GenerateKeys(t *testing.T, accNames []string) map[string]*Account {
// 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) {
func GenerateTestTxs(t *testing.T, instructions Instructions) ([][]*common.L1Tx, [][]*common.L1Tx, [][]*common.PoolL2Tx, []common.Token) {
accounts := GenerateKeys(t, instructions.Accounts)
l1CreatedAccounts := make(map[string]*Account)
@@ -148,13 +148,32 @@ func GenerateTestTxs(t *testing.T, instructions Instructions) ([][]*common.L1Tx,
l1Txs = append(l1Txs, batchL1Txs)
coordinatorL1Txs = append(coordinatorL1Txs, batchCoordinatorL1Txs)
poolL2Txs = append(poolL2Txs, batchPoolL2Txs)
return l1Txs, coordinatorL1Txs, poolL2Txs
tokens := []common.Token{}
for i := 0; i < len(poolL2Txs); i++ {
for j := 0; j < len(poolL2Txs[i]); j++ {
id := poolL2Txs[i][j].TokenID
found := false
for k := 0; k < len(tokens); k++ {
if tokens[k].TokenID == id {
found = true
break
}
}
if !found {
tokens = append(tokens, common.Token{
TokenID: id,
EthBlockNum: 1,
EthAddr: ethCommon.BigToAddress(big.NewInt(int64(i*10000 + j))),
})
}
}
}
return l1Txs, coordinatorL1Txs, poolL2Txs, tokens
}
// 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) {
func GenerateTestTxsFromSet(t *testing.T, set string) ([][]*common.L1Tx, [][]*common.L1Tx, [][]*common.PoolL2Tx, []common.Token) {
parser := NewParser(strings.NewReader(set))
instructions, err := parser.Parse()
require.Nil(t, err)

View File

@@ -29,7 +29,7 @@ func TestGenerateTestL2Txs(t *testing.T) {
instructions, err := parser.Parse()
assert.Nil(t, err)
l1txs, coordinatorL1txs, l2txs := GenerateTestTxs(t, instructions)
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]))