mirror of
https://github.com/arnaucube/hermez-node.git
synced 2026-02-07 03:16:45 +01:00
L1Tx Codec
This commit is contained in:
@@ -7,6 +7,14 @@ import (
|
|||||||
"github.com/iden3/go-iden3-crypto/babyjub"
|
"github.com/iden3/go-iden3-crypto/babyjub"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
fromBJJCompressedB = 256
|
||||||
|
fromEthAddrB = 160
|
||||||
|
f16B = 16
|
||||||
|
tokenIDB = 32
|
||||||
|
cidXB = 32
|
||||||
|
)
|
||||||
|
|
||||||
// L1Tx is a struct that represents a L1 tx
|
// L1Tx is a struct that represents a L1 tx
|
||||||
type L1Tx struct {
|
type L1Tx struct {
|
||||||
// Stored in DB: mandatory fileds
|
// Stored in DB: mandatory fileds
|
||||||
@@ -23,6 +31,7 @@ type L1Tx struct {
|
|||||||
LoadAmount *big.Int `meddler:"load_amount,bigint"`
|
LoadAmount *big.Int `meddler:"load_amount,bigint"`
|
||||||
EthBlockNum uint64 `meddler:"eth_block_num"` // Ethereum Block Number in which this L1Tx was added to the queue
|
EthBlockNum uint64 `meddler:"eth_block_num"` // Ethereum Block Number in which this L1Tx was added to the queue
|
||||||
Type TxType `meddler:"tx_type"`
|
Type TxType `meddler:"tx_type"`
|
||||||
|
BatchNum BatchNum `meddler:"-"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// Tx returns a *Tx from the L1Tx
|
// Tx returns a *Tx from the L1Tx
|
||||||
@@ -35,3 +44,71 @@ func (tx *L1Tx) Tx() *Tx {
|
|||||||
Type: tx.Type,
|
Type: tx.Type,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Bytes encodes a L1Tx into []byte
|
||||||
|
func (tx *L1Tx) Bytes(nLevels int) []byte {
|
||||||
|
res := big.NewInt(0)
|
||||||
|
res = res.Add(res, big.NewInt(0).Or(big.NewInt(0), tx.ToIdx.BigInt()))
|
||||||
|
res = res.Add(res, big.NewInt(0).Lsh(big.NewInt(0).Or(big.NewInt(0), big.NewInt(int64(tx.TokenID))), uint(nLevels)))
|
||||||
|
res = res.Add(res, big.NewInt(0).Lsh(big.NewInt(0).Or(big.NewInt(0), tx.Amount), uint(nLevels+tokenIDB)))
|
||||||
|
res = res.Add(res, big.NewInt(0).Lsh(big.NewInt(0).Or(big.NewInt(0), tx.LoadAmount), uint(nLevels+tokenIDB+f16B)))
|
||||||
|
res = res.Add(res, big.NewInt(0).Lsh(big.NewInt(0).Or(big.NewInt(0), tx.FromIdx.BigInt()), uint(nLevels+tokenIDB+2*f16B)))
|
||||||
|
|
||||||
|
fromBJJ := big.NewInt(0)
|
||||||
|
fromBJJ.SetString(tx.FromBJJ.String(), 16)
|
||||||
|
fromBJJCompressed := big.NewInt(0).Or(big.NewInt(0), fromBJJ)
|
||||||
|
res = res.Add(res, big.NewInt(0).Lsh(fromBJJCompressed, uint(2*nLevels+tokenIDB+2*f16B)))
|
||||||
|
|
||||||
|
fromEthAddr := big.NewInt(0).Or(big.NewInt(0), tx.FromEthAddr.Hash().Big())
|
||||||
|
res = res.Add(res, big.NewInt(0).Lsh(fromEthAddr, uint(fromBJJCompressedB+2*nLevels+tokenIDB+2*f16B)))
|
||||||
|
|
||||||
|
return res.Bytes()
|
||||||
|
}
|
||||||
|
|
||||||
|
// L1TxFromBytes decodes a L1Tx from []byte
|
||||||
|
func L1TxFromBytes(l1TxEncoded []byte) (*L1Tx, error) {
|
||||||
|
l1Tx := &L1Tx{}
|
||||||
|
var idxB uint = cidXB
|
||||||
|
|
||||||
|
l1TxEncodedBI := big.NewInt(0)
|
||||||
|
l1TxEncodedBI.SetBytes(l1TxEncoded)
|
||||||
|
|
||||||
|
toIdx, err := IdxFromBigInt(extract(l1TxEncodedBI, 0, idxB))
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
l1Tx.ToIdx = toIdx
|
||||||
|
|
||||||
|
l1Tx.TokenID = TokenID(extract(l1TxEncodedBI, idxB, tokenIDB).Uint64())
|
||||||
|
l1Tx.Amount = extract(l1TxEncodedBI, idxB+tokenIDB, f16B)
|
||||||
|
l1Tx.LoadAmount = extract(l1TxEncodedBI, idxB+tokenIDB+f16B, f16B)
|
||||||
|
fromIdx, err := IdxFromBigInt(extract(l1TxEncodedBI, idxB+tokenIDB+2*f16B, f16B))
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
l1Tx.FromIdx = fromIdx
|
||||||
|
|
||||||
|
var pkComp babyjub.PublicKeyComp
|
||||||
|
copy(pkComp[:], extract(l1TxEncodedBI, 2*idxB+tokenIDB+2*f16B, fromBJJCompressedB).Bytes())
|
||||||
|
pk, err := pkComp.Decompress()
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
l1Tx.FromBJJ = pk
|
||||||
|
|
||||||
|
l1Tx.FromEthAddr = ethCommon.BigToAddress(extract(l1TxEncodedBI, fromBJJCompressedB+2*idxB+tokenIDB+2*f16B, fromEthAddrB))
|
||||||
|
|
||||||
|
return l1Tx, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// extract masks and shifts a bigInt
|
||||||
|
func extract(num *big.Int, origin uint, len uint) *big.Int {
|
||||||
|
mask := big.NewInt(0).Sub(big.NewInt(0).Lsh(big.NewInt(1), len), big.NewInt(1))
|
||||||
|
return big.NewInt(0).And(big.NewInt(0).Rsh(num, origin), mask)
|
||||||
|
}
|
||||||
|
|||||||
43
common/l1tx_test.go
Normal file
43
common/l1tx_test.go
Normal file
@@ -0,0 +1,43 @@
|
|||||||
|
package common
|
||||||
|
|
||||||
|
import (
|
||||||
|
"math/big"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
ethCommon "github.com/ethereum/go-ethereum/common"
|
||||||
|
"github.com/iden3/go-iden3-crypto/babyjub"
|
||||||
|
"github.com/iden3/go-iden3-crypto/utils"
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
"github.com/stretchr/testify/require"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestL1TxCodec(t *testing.T) {
|
||||||
|
var pkComp babyjub.PublicKeyComp
|
||||||
|
err := pkComp.UnmarshalText([]byte("0x56ca90f80d7c374ae7485e9bcc47d4ac399460948da6aeeb899311097925a72c"))
|
||||||
|
require.Nil(t, err)
|
||||||
|
|
||||||
|
pk, err := pkComp.Decompress()
|
||||||
|
require.Nil(t, err)
|
||||||
|
|
||||||
|
l1Tx := L1Tx{
|
||||||
|
ToIdx: 3,
|
||||||
|
TokenID: 5,
|
||||||
|
Amount: big.NewInt(1),
|
||||||
|
LoadAmount: big.NewInt(2),
|
||||||
|
FromIdx: 2,
|
||||||
|
FromBJJ: pk,
|
||||||
|
FromEthAddr: ethCommon.HexToAddress("0xc58d29fA6e86E4FAe04DDcEd660d45BCf3Cb2370"),
|
||||||
|
}
|
||||||
|
|
||||||
|
expected, err := utils.HexDecode("c58d29fa6e86e4fae04ddced660d45bcf3cb237056ca90f80d7c374ae7485e9bcc47d4ac399460948da6aeeb899311097925a72c00000002000200010000000500000003")
|
||||||
|
require.Nil(t, err)
|
||||||
|
|
||||||
|
encodedData := l1Tx.Bytes(32)
|
||||||
|
assert.Equal(t, expected, encodedData)
|
||||||
|
|
||||||
|
decodedData, err := L1TxFromBytes(encodedData)
|
||||||
|
require.Nil(t, err)
|
||||||
|
|
||||||
|
encodedData2 := decodedData.Bytes(32)
|
||||||
|
assert.Equal(t, encodedData, encodedData2)
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user