Update Common & StateDB & ZKInputs to last protocol version

- Add InvalidData flag to L1Tx
- Add BytesDataAvailability to L1Tx
- Update ZKInputs & HashGlobalInputs to last spec of the protocol
(massive migrations)
- TxProcessor check correctness of L1Txs

Compatible with hermeznetwork/commonjs v0.0.4
(c345239bba)
This commit is contained in:
arnaucube
2020-11-25 20:07:37 +01:00
parent 0c83417881
commit dde9250429
17 changed files with 442 additions and 90 deletions

View File

@@ -36,6 +36,11 @@ func (bn BatchNum) Bytes() []byte {
return batchNumBytes[:]
}
// BigInt returns a *big.Int representing the BatchNum
func (bn BatchNum) BigInt() *big.Int {
return big.NewInt(int64(bn))
}
// BatchNumFromBytes returns BatchNum from a []byte
func BatchNumFromBytes(b []byte) (BatchNum, error) {
if len(b) != batchNumBytesLen {

View File

@@ -37,10 +37,14 @@ type L1Tx struct {
ToIdx Idx `meddler:"to_idx"` // ToIdx is ignored in L1Tx/Deposit, but used in the L1Tx/DepositAndTransfer
TokenID TokenID `meddler:"token_id"`
Amount *big.Int `meddler:"amount,bigint"`
LoadAmount *big.Int `meddler:"load_amount,bigint"`
EthBlockNum int64 `meddler:"eth_block_num"` // Ethereum Block Number in which this L1Tx was added to the queue
Type TxType `meddler:"type"`
BatchNum *BatchNum `meddler:"batch_num"`
// EffectiveAmount only applies to L1UserTx.
EffectiveAmount *big.Int `meddler:"effective_amount,bigintnull"`
LoadAmount *big.Int `meddler:"load_amount,bigint"`
// EffectiveLoadAmount only applies to L1UserTx.
EffectiveLoadAmount *big.Int `meddler:"effective_load_amount,bigintnull"`
EthBlockNum int64 `meddler:"eth_block_num"` // Ethereum Block Number in which this L1Tx was added to the queue
Type TxType `meddler:"type"`
BatchNum *BatchNum `meddler:"batch_num"`
}
// NewL1Tx returns the given L1Tx with the TxId & Type parameters calculated
@@ -117,7 +121,7 @@ func (tx *L1Tx) CalcTxID() (*TxID, error) {
// Tx returns a *Tx from the L1Tx
func (tx L1Tx) Tx() Tx {
f := new(big.Float).SetInt(tx.Amount)
f := new(big.Float).SetInt(tx.EffectiveAmount)
amountFloat, _ := f.Float64()
userOrigin := new(bool)
*userOrigin = tx.UserOrigin
@@ -128,14 +132,14 @@ func (tx L1Tx) Tx() Tx {
Position: tx.Position,
FromIdx: tx.FromIdx,
ToIdx: tx.ToIdx,
Amount: tx.Amount,
Amount: tx.EffectiveAmount,
AmountFloat: amountFloat,
TokenID: tx.TokenID,
ToForgeL1TxsNum: tx.ToForgeL1TxsNum,
UserOrigin: userOrigin,
FromEthAddr: tx.FromEthAddr,
FromBJJ: tx.FromBJJ,
LoadAmount: tx.LoadAmount,
LoadAmount: tx.EffectiveLoadAmount,
EthBlockNum: tx.EthBlockNum,
}
if tx.LoadAmount != nil {
@@ -183,6 +187,34 @@ func (tx L1Tx) TxCompressedData() (*big.Int, error) {
return bi, nil
}
// BytesDataAvailability encodes a L1Tx into []byte for the Data Availability
func (tx *L1Tx) BytesDataAvailability(nLevels uint32) ([]byte, error) {
idxLen := nLevels / 8 //nolint:gomnd
b := make([]byte, ((nLevels*2)+16+8)/8) //nolint:gomnd
fromIdxBytes, err := tx.FromIdx.Bytes()
if err != nil {
return nil, err
}
copy(b[0:idxLen], fromIdxBytes[6-idxLen:])
toIdxBytes, err := tx.ToIdx.Bytes()
if err != nil {
return nil, err
}
copy(b[idxLen:idxLen*2], toIdxBytes[6-idxLen:])
if tx.EffectiveAmount != nil {
amountFloat16, err := NewFloat16(tx.EffectiveAmount)
if err != nil {
return nil, err
}
copy(b[idxLen*2:idxLen*2+2], amountFloat16.Bytes())
}
// fee = 0 (as is L1Tx) b[10:11]
return b[:], nil
}
// BytesGeneric returns the generic representation of a L1Tx. This method is
// used to compute the []byte representation of a L1UserTx, and also to compute
// the L1TxData for the ZKInputs (at the HashGlobalInputs), using this method

View File

@@ -65,6 +65,28 @@ func TestL1TxCompressedData(t *testing.T) {
assert.Equal(t, "050004000000000003000000000002000100000000", hex.EncodeToString(txCompressedData.Bytes()))
}
func TestBytesDataAvailability(t *testing.T) {
tx := L1Tx{
FromIdx: 2,
ToIdx: 3,
Amount: big.NewInt(4),
TokenID: 5,
}
txCompressedData, err := tx.BytesDataAvailability(32)
assert.Nil(t, err)
assert.Equal(t, "0000000200000003000000", hex.EncodeToString(txCompressedData))
tx = L1Tx{
FromIdx: 2,
ToIdx: 3,
EffectiveAmount: big.NewInt(4),
TokenID: 5,
}
txCompressedData, err = tx.BytesDataAvailability(32)
assert.Nil(t, err)
assert.Equal(t, "0000000200000003000400", hex.EncodeToString(txCompressedData))
}
func TestL1userTxByteParsers(t *testing.T) {
var pkComp babyjub.PublicKeyComp
pkCompL := []byte("0x56ca90f80d7c374ae7485e9bcc47d4ac399460948da6aeeb899311097925a72c")

View File

@@ -103,8 +103,8 @@ func L2TxsToPoolL2Txs(txs []L2Tx) []PoolL2Tx {
return r
}
// Bytes encodes a L2Tx into []byte
func (tx L2Tx) Bytes(nLevels uint32) ([]byte, error) {
// BytesDataAvailability encodes a L2Tx into []byte for the Data Availability
func (tx L2Tx) BytesDataAvailability(nLevels uint32) ([]byte, error) {
idxLen := nLevels / 8 //nolint:gomnd
b := make([]byte, ((nLevels*2)+16+8)/8) //nolint:gomnd

View File

@@ -32,7 +32,7 @@ func TestL2TxByteParsers(t *testing.T) {
}
// Data from the compatibility test
expected := "00000101000001002b16c9"
encodedData, err := l2Tx.Bytes(32)
encodedData, err := l2Tx.BytesDataAvailability(32)
require.Nil(t, err)
assert.Equal(t, expected, hex.EncodeToString(encodedData))

View File

@@ -117,7 +117,6 @@ const (
)
// Tx is a struct used by the TxSelector & BatchBuilder as a generic type generated from L1Tx & PoolL2Tx
// TODO: this should be changed for "mini Tx"
type Tx struct {
// Generic
IsL1 bool `meddler:"is_l1"`

View File

@@ -32,9 +32,10 @@ type ZKMetadata struct {
// is constant for all circuits: 64)
MaxFeeIdxs uint32
L1TxsData [][]byte
L2TxsData [][]byte
ChainID uint16
L1TxsData [][]byte
L1TxsDataAvailability [][]byte
L2TxsData [][]byte
ChainID uint16
NewLastIdxRaw Idx
NewStateRootRaw *merkletree.Hash
@@ -49,6 +50,8 @@ type ZKInputs struct {
// General
//
// CurrentNumBatch is the current batch number processed
CurrentNumBatch *big.Int `json:"currentNumBatch"` // uint32
// inputs for final `hashGlobalInputs`
// OldLastIdx is the last index assigned to an account
OldLastIdx *big.Int `json:"oldLastIdx"` // uint64 (max nLevels bits)
@@ -72,6 +75,9 @@ type ZKInputs struct {
TxCompressedData []*big.Int `json:"txCompressedData"` // big.Int (max 251 bits), len: [nTx]
// TxCompressedDataV2, only used in L2Txs, in L1Txs is set to 0
TxCompressedDataV2 []*big.Int `json:"txCompressedDataV2"` // big.Int (max 193 bits), len: [nTx]
// MaxNumBatch is the maximum allowed batch number when the transaction
// can be processed
MaxNumBatch []*big.Int `json:"maxNumBatch"` // uint32
// FromIdx
FromIdx []*big.Int `json:"fromIdx"` // uint64 (max nLevels bits), len: [nTx]
@@ -266,7 +272,7 @@ func (z ZKInputs) MarshalJSON() ([]byte, error) {
}
// NewZKInputs returns a pointer to an initialized struct of ZKInputs
func NewZKInputs(nTx, maxL1Tx, maxTx, maxFeeIdxs, nLevels uint32) *ZKInputs {
func NewZKInputs(nTx, maxL1Tx, maxTx, maxFeeIdxs, nLevels uint32, currentNumBatch *big.Int) *ZKInputs {
zki := &ZKInputs{}
zki.Metadata.NTx = nTx
zki.Metadata.MaxFeeIdxs = maxFeeIdxs
@@ -276,15 +282,17 @@ func NewZKInputs(nTx, maxL1Tx, maxTx, maxFeeIdxs, nLevels uint32) *ZKInputs {
zki.Metadata.MaxTx = maxTx
// General
zki.CurrentNumBatch = currentNumBatch
zki.OldLastIdx = big.NewInt(0)
zki.OldStateRoot = big.NewInt(0)
zki.GlobalChainID = big.NewInt(0)
zki.GlobalChainID = big.NewInt(0) // TODO pass by parameter
zki.FeeIdxs = newSlice(maxFeeIdxs)
zki.FeePlanTokens = newSlice(maxFeeIdxs)
// Txs
zki.TxCompressedData = newSlice(nTx)
zki.TxCompressedDataV2 = newSlice(nTx)
zki.MaxNumBatch = newSlice(nTx)
zki.FromIdx = newSlice(nTx)
zki.AuxFromIdx = newSlice(nTx)
zki.ToIdx = newSlice(nTx)
@@ -451,6 +459,12 @@ func (z ZKInputs) ToHashGlobalData() ([]byte, error) {
}
b = append(b, l1TxsData...)
var l1TxsDataAvailability []byte
for i := 0; i < len(z.Metadata.L1TxsDataAvailability); i++ {
l1TxsDataAvailability = append(l1TxsDataAvailability, z.Metadata.L1TxsDataAvailability[i]...)
}
b = append(b, l1TxsDataAvailability...)
// [MAX_TX*(2*NLevels + 24) bits] L2TxsData
var l2TxsData []byte
l2TxDataLen := 2*z.Metadata.NLevels + 24 //nolint:gomnd
@@ -463,9 +477,9 @@ func (z ZKInputs) ToHashGlobalData() ([]byte, error) {
return nil, fmt.Errorf("len(l2TxsData): %d, expected: %d", len(l2TxsData), expectedL2TxsDataLen)
}
l2TxsPadding := make([]byte, (int(z.Metadata.MaxTx)-len(z.Metadata.L2TxsData))*int(l2TxDataLen)/8) //nolint:gomnd
b = append(b, l2TxsPadding...)
b = append(b, l2TxsData...)
l2TxsPadding := make([]byte, (int(z.Metadata.MaxTx)-len(z.Metadata.L1TxsDataAvailability)-len(z.Metadata.L2TxsData))*int(l2TxDataLen)/8) //nolint:gomnd
b = append(b, l2TxsPadding...)
// [NLevels * MAX_TOKENS_FEE bits] feeTxsData
for i := 0; i < len(z.FeeIdxs); i++ {
@@ -486,5 +500,11 @@ func (z ZKInputs) ToHashGlobalData() ([]byte, error) {
binary.BigEndian.PutUint16(chainID[:], z.Metadata.ChainID)
b = append(b, chainID[:]...)
// [32 bits] currentNumBatch
currNumBatchBytes := z.CurrentNumBatch.Bytes()
var currNumBatch [4]byte
copy(currNumBatch[4-len(currNumBatchBytes):], currNumBatchBytes)
b = append(b, currNumBatch[:]...)
return b, nil
}

View File

@@ -2,13 +2,14 @@ package common
import (
"encoding/json"
"math/big"
"testing"
"github.com/stretchr/testify/require"
)
func TestZKInputs(t *testing.T) {
zki := NewZKInputs(100, 16, 512, 24, 32)
zki := NewZKInputs(100, 16, 512, 24, 32, big.NewInt(1))
_, err := json.Marshal(zki)
require.Nil(t, err)
// fmt.Println(string(s))