arnaucube
arnaucube/hermez-nodePublic Self-hosted repository
hermez-node/common/l1tx.go
common/l1tx.goRaw
  1package common
  2
  3import (
  4	"fmt"
  5	"math/big"
  6
  7	ethCommon "github.com/ethereum/go-ethereum/common"
  8	"github.com/hermeznetwork/hermez-node/utils"
  9	"github.com/iden3/go-iden3-crypto/babyjub"
 10)
 11
 12const (
 13	// L1TxBytesLen is the length of the byte array that represents the L1Tx
 14	L1TxBytesLen = 68
 15)
 16
 17// L1Tx is a struct that represents a L1 tx
 18type L1Tx struct {
 19	// Stored in DB: mandatory fileds
 20	TxID            TxID
 21	ToForgeL1TxsNum uint32 // toForgeL1TxsNum in which the tx was forged / will be forged
 22	Position        int
 23	UserOrigin      bool // true if the tx was originated by a user, false if it was aoriginated by a coordinator. Note that this differ from the spec for implementation simplification purpposes
 24	FromIdx         Idx  // FromIdx is used by L1Tx/Deposit to indicate the Idx receiver of the L1Tx.LoadAmount (deposit)
 25	FromEthAddr     ethCommon.Address
 26	FromBJJ         *babyjub.PublicKey
 27	ToIdx           Idx // ToIdx is ignored in L1Tx/Deposit, but used in the L1Tx/DepositAndTransfer
 28	TokenID         TokenID
 29	Amount          *big.Int
 30	LoadAmount      *big.Int
 31	EthBlockNum     int64 // Ethereum Block Number in which this L1Tx was added to the queue
 32	Type            TxType
 33	BatchNum        BatchNum
 34}
 35
 36// Tx returns a *Tx from the L1Tx
 37func (tx *L1Tx) Tx() *Tx {
 38	f := new(big.Float).SetInt(tx.Amount)
 39	amountFloat, _ := f.Float64()
 40	genericTx := &Tx{
 41		IsL1:            true,
 42		TxID:            tx.TxID,
 43		Type:            tx.Type,
 44		Position:        tx.Position,
 45		FromIdx:         tx.FromIdx,
 46		ToIdx:           tx.ToIdx,
 47		Amount:          tx.Amount,
 48		AmountFloat:     amountFloat,
 49		TokenID:         tx.TokenID,
 50		ToForgeL1TxsNum: tx.ToForgeL1TxsNum,
 51		UserOrigin:      tx.UserOrigin,
 52		FromEthAddr:     tx.FromEthAddr,
 53		FromBJJ:         tx.FromBJJ,
 54		LoadAmount:      tx.LoadAmount,
 55		EthBlockNum:     tx.EthBlockNum,
 56	}
 57	if tx.LoadAmount != nil {
 58		lf := new(big.Float).SetInt(tx.LoadAmount)
 59		loadAmountFloat, _ := lf.Float64()
 60		genericTx.LoadAmountFloat = loadAmountFloat
 61	}
 62	return genericTx
 63}
 64
 65// Bytes encodes a L1Tx into []byte
 66func (tx *L1Tx) Bytes(nLevels int) ([]byte, error) {
 67	var b [68]byte
 68	copy(b[0:4], tx.ToIdx.Bytes())
 69	copy(b[4:8], tx.TokenID.Bytes())
 70	amountFloat16, err := utils.NewFloat16(tx.Amount)
 71	if err != nil {
 72		return nil, err
 73	}
 74	copy(b[8:10], amountFloat16.Bytes())
 75	loadAmountFloat16, err := utils.NewFloat16(tx.LoadAmount)
 76	if err != nil {
 77		return nil, err
 78	}
 79	copy(b[10:12], loadAmountFloat16.Bytes())
 80	copy(b[12:16], tx.FromIdx.Bytes())
 81	pkComp := tx.FromBJJ.Compress()
 82	copy(b[16:48], SwapEndianness(pkComp[:]))
 83	copy(b[48:68], SwapEndianness(tx.FromEthAddr.Bytes()))
 84	return SwapEndianness(b[:]), nil
 85}
 86
 87// L1TxFromBytes decodes a L1Tx from []byte
 88func L1TxFromBytes(bRaw []byte) (*L1Tx, error) {
 89	if len(bRaw) != L1TxBytesLen {
 90		return nil, fmt.Errorf("Can not parse L1Tx bytes, expected length %d, current: %d", 68, len(bRaw))
 91	}
 92
 93	b := SwapEndianness(bRaw)
 94	tx := &L1Tx{}
 95	var err error
 96	tx.ToIdx, err = IdxFromBytes(b[0:4])
 97	if err != nil {
 98		return nil, err
 99	}
100	tx.TokenID, err = TokenIDFromBytes(b[4:8])
101	if err != nil {
102		return nil, err
103	}
104	tx.Amount = new(big.Int).SetBytes(SwapEndianness(b[8:10]))
105	tx.LoadAmount = new(big.Int).SetBytes(SwapEndianness(b[10:12]))
106	tx.FromIdx, err = IdxFromBytes(b[12:16])
107	if err != nil {
108		return nil, err
109	}
110	pkCompB := SwapEndianness(b[16:48])
111	var pkComp babyjub.PublicKeyComp
112	copy(pkComp[:], pkCompB)
113	tx.FromBJJ, err = pkComp.Decompress()
114	if err != nil {
115		return nil, err
116	}
117	tx.FromEthAddr = ethCommon.BytesToAddress(SwapEndianness(b[48:68]))
118	return tx, nil
119}