arnaucube
arnaucube/hermez-nodePublic Self-hosted repository
hermez-node/common/tx.go
common/tx.goRaw
  1package common
  2
  3import (
  4	"bytes"
  5	"database/sql/driver"
  6	"encoding/hex"
  7	"errors"
  8	"fmt"
  9	"math/big"
 10	"strings"
 11
 12	ethCommon "github.com/ethereum/go-ethereum/common"
 13	"github.com/hermeznetwork/tracerr"
 14	"github.com/iden3/go-iden3-crypto/babyjub"
 15)
 16
 17const (
 18	// TxIDPrefixL1UserTx is the prefix that determines that the TxID is for
 19	// a L1UserTx
 20	//nolinter:gomnd
 21	TxIDPrefixL1UserTx = byte(0)
 22
 23	// TxIDPrefixL1CoordTx is the prefix that determines that the TxID is
 24	// for a L1CoordinatorTx
 25	//nolinter:gomnd
 26	TxIDPrefixL1CoordTx = byte(1)
 27
 28	// TxIDPrefixL2Tx is the prefix that determines that the TxID is for a
 29	// L2Tx (or PoolL2Tx)
 30	//nolinter:gomnd
 31	TxIDPrefixL2Tx = byte(2)
 32
 33	// TxIDLen is the length of the TxID byte array
 34	TxIDLen = 33
 35)
 36
 37var (
 38	// SignatureConstantBytes contains the SignatureConstant in byte array
 39	// format, which is equivalent to 3322668559 as uint32 in byte array in
 40	// big endian representation.
 41	SignatureConstantBytes = []byte{198, 11, 230, 15}
 42)
 43
 44// TxID is the identifier of a Hermez network transaction
 45type TxID [TxIDLen]byte
 46
 47// Scan implements Scanner for database/sql.
 48func (txid *TxID) Scan(src interface{}) error {
 49	srcB, ok := src.([]byte)
 50	if !ok {
 51		return tracerr.Wrap(fmt.Errorf("can't scan %T into TxID", src))
 52	}
 53	if len(srcB) != TxIDLen {
 54		return tracerr.Wrap(fmt.Errorf("can't scan []byte of len %d into TxID, need %d",
 55			len(srcB), TxIDLen))
 56	}
 57	copy(txid[:], srcB)
 58	return nil
 59}
 60
 61// Value implements valuer for database/sql.
 62func (txid TxID) Value() (driver.Value, error) {
 63	return txid[:], nil
 64}
 65
 66// String returns a string hexadecimal representation of the TxID
 67func (txid TxID) String() string {
 68	return "0x" + hex.EncodeToString(txid[:])
 69}
 70
 71// NewTxIDFromString returns a string hexadecimal representation of the TxID
 72func NewTxIDFromString(idStr string) (TxID, error) {
 73	txid := TxID{}
 74	idStr = strings.TrimPrefix(idStr, "0x")
 75	decoded, err := hex.DecodeString(idStr)
 76	if err != nil {
 77		return TxID{}, tracerr.Wrap(err)
 78	}
 79	if len(decoded) != TxIDLen {
 80		return txid, tracerr.Wrap(errors.New("Invalid idStr"))
 81	}
 82	copy(txid[:], decoded)
 83	return txid, nil
 84}
 85
 86// MarshalText marshals a TxID
 87func (txid TxID) MarshalText() ([]byte, error) {
 88	return []byte(txid.String()), nil
 89}
 90
 91// UnmarshalText unmarshalls a TxID
 92func (txid *TxID) UnmarshalText(data []byte) error {
 93	idStr := string(data)
 94	id, err := NewTxIDFromString(idStr)
 95	if err != nil {
 96		return tracerr.Wrap(err)
 97	}
 98	*txid = id
 99	return nil
100}
101
102// TxType is a string that represents the type of a Hermez network transaction
103type TxType string
104
105const (
106	// TxTypeExit represents L2->L1 token transfer.  A leaf for this account appears in the exit
107	// tree of the block
108	TxTypeExit TxType = "Exit"
109	// TxTypeTransfer represents L2->L2 token transfer
110	TxTypeTransfer TxType = "Transfer"
111	// TxTypeDeposit represents L1->L2 transfer
112	TxTypeDeposit TxType = "Deposit"
113	// TxTypeCreateAccountDeposit represents creation of a new leaf in the state tree
114	// (newAcconut) + L1->L2 transfer
115	TxTypeCreateAccountDeposit TxType = "CreateAccountDeposit"
116	// TxTypeCreateAccountDepositTransfer represents L1->L2 transfer + L2->L2 transfer
117	TxTypeCreateAccountDepositTransfer TxType = "CreateAccountDepositTransfer"
118	// TxTypeDepositTransfer TBD
119	TxTypeDepositTransfer TxType = "DepositTransfer"
120	// TxTypeForceTransfer TBD
121	TxTypeForceTransfer TxType = "ForceTransfer"
122	// TxTypeForceExit TBD
123	TxTypeForceExit TxType = "ForceExit"
124	// TxTypeTransferToEthAddr TBD
125	TxTypeTransferToEthAddr TxType = "TransferToEthAddr"
126	// TxTypeTransferToBJJ TBD
127	TxTypeTransferToBJJ TxType = "TransferToBJJ"
128)
129
130// Tx is a struct used by the TxSelector & BatchBuilder as a generic type generated from L1Tx &
131// PoolL2Tx
132type Tx struct {
133	// Generic
134	IsL1        bool     `meddler:"is_l1"`
135	TxID        TxID     `meddler:"id"`
136	Type        TxType   `meddler:"type"`
137	Position    int      `meddler:"position"`
138	FromIdx     Idx      `meddler:"from_idx"`
139	ToIdx       Idx      `meddler:"to_idx"`
140	Amount      *big.Int `meddler:"amount,bigint"`
141	AmountFloat float64  `meddler:"amount_f"`
142	TokenID     TokenID  `meddler:"token_id"`
143	USD         *float64 `meddler:"amount_usd"`
144	// BatchNum in which this tx was forged. If the tx is L2, this must be != 0
145	BatchNum *BatchNum `meddler:"batch_num"`
146	// Ethereum Block Number in which this L1Tx was added to the queue
147	EthBlockNum int64 `meddler:"eth_block_num"`
148	// L1
149	// ToForgeL1TxsNum in which the tx was forged / will be forged
150	ToForgeL1TxsNum *int64 `meddler:"to_forge_l1_txs_num"`
151	// UserOrigin is set to true if the tx was originated by a user, false if it was aoriginated
152	// by a coordinator. Note that this differ from the spec for implementation simplification
153	// purpposes
154	UserOrigin         *bool                 `meddler:"user_origin"`
155	FromEthAddr        ethCommon.Address     `meddler:"from_eth_addr"`
156	FromBJJ            babyjub.PublicKeyComp `meddler:"from_bjj"`
157	DepositAmount      *big.Int              `meddler:"deposit_amount,bigintnull"`
158	DepositAmountFloat *float64              `meddler:"deposit_amount_f"`
159	DepositAmountUSD   *float64              `meddler:"deposit_amount_usd"`
160	// L2
161	Fee    *FeeSelector `meddler:"fee"`
162	FeeUSD *float64     `meddler:"fee_usd"`
163	Nonce  *Nonce       `meddler:"nonce"`
164}
165
166func (tx *Tx) String() string {
167	buf := bytes.NewBufferString("")
168	fmt.Fprintf(buf, "Type: %s, ", tx.Type)
169	fmt.Fprintf(buf, "FromIdx: %s, ", tx.FromIdx)
170	if tx.Type == TxTypeTransfer ||
171		tx.Type == TxTypeDepositTransfer ||
172		tx.Type == TxTypeCreateAccountDepositTransfer {
173		fmt.Fprintf(buf, "ToIdx: %s, ", tx.ToIdx)
174	}
175	if tx.Type == TxTypeDeposit ||
176		tx.Type == TxTypeDepositTransfer ||
177		tx.Type == TxTypeCreateAccountDepositTransfer {
178		fmt.Fprintf(buf, "DepositAmount: %d, ", tx.DepositAmount)
179	}
180	if tx.Type != TxTypeDeposit {
181		fmt.Fprintf(buf, "Amount: %s, ", tx.Amount)
182	}
183	if tx.Type == TxTypeTransfer ||
184		tx.Type == TxTypeDepositTransfer ||
185		tx.Type == TxTypeCreateAccountDepositTransfer {
186		fmt.Fprintf(buf, "Fee: %d, ", tx.Fee)
187	}
188	fmt.Fprintf(buf, "TokenID: %d", tx.TokenID)
189
190	return buf.String()
191}
192
193// L1Tx returns a *L1Tx from the Tx
194func (tx *Tx) L1Tx() (*L1Tx, error) {
195	return &L1Tx{
196		TxID:            tx.TxID,
197		ToForgeL1TxsNum: tx.ToForgeL1TxsNum,
198		Position:        tx.Position,
199		UserOrigin:      *tx.UserOrigin,
200		FromIdx:         tx.FromIdx,
201		FromEthAddr:     tx.FromEthAddr,
202		FromBJJ:         tx.FromBJJ,
203		ToIdx:           tx.ToIdx,
204		TokenID:         tx.TokenID,
205		Amount:          tx.Amount,
206		DepositAmount:   tx.DepositAmount,
207		EthBlockNum:     tx.EthBlockNum,
208		Type:            tx.Type,
209		BatchNum:        tx.BatchNum,
210	}, nil
211}