bitxhub/api/grpc/transaction.go

107 lines
2.5 KiB
Go

package grpc
import (
"context"
"fmt"
"time"
"github.com/meshplus/bitxhub-kit/types"
"github.com/meshplus/bitxhub-model/pb"
)
// SendTransaction handles transaction sent by the client.
// If the transaction is valid, it will return the transaction hash.
func (cbs *ChainBrokerService) SendTransaction(ctx context.Context, tx *pb.SendTransactionRequest) (*pb.TransactionHashMsg, error) {
if !cbs.api.Broker().OrderReady() {
return nil, fmt.Errorf("the system is temporarily unavailable")
}
if err := cbs.checkTransaction(tx); err != nil {
return nil, err
}
hash, err := cbs.sendTransaction(tx)
if err != nil {
return nil, err
}
return &pb.TransactionHashMsg{TxHash: hash}, nil
}
func (cbs *ChainBrokerService) checkTransaction(tx *pb.SendTransactionRequest) error {
if tx.Data == nil {
return fmt.Errorf("tx data can't be empty")
}
if tx.Data.Type == pb.TransactionData_NORMAL && tx.Data.Amount == 0 {
return fmt.Errorf("amount can't be 0 in transfer tx")
}
emptyAddress := types.Address{}.Hex()
if tx.From.Hex() == emptyAddress {
return fmt.Errorf("from can't be empty")
}
if tx.From == tx.To {
return fmt.Errorf("from can`t be the same as to")
}
if tx.To.Hex() == emptyAddress && len(tx.Data.Payload) == 0 {
return fmt.Errorf("can't deploy empty contract")
}
if tx.Timestamp < time.Now().UnixNano()-10*time.Minute.Nanoseconds() ||
tx.Timestamp > time.Now().UnixNano()+10*time.Minute.Nanoseconds() {
return fmt.Errorf("timestamp is illegal")
}
if tx.Nonce <= 0 {
return fmt.Errorf("nonce is illegal")
}
if len(tx.Signature) == 0 {
return fmt.Errorf("signature can't be empty")
}
return nil
}
func (cbs *ChainBrokerService) sendTransaction(req *pb.SendTransactionRequest) (string, error) {
tx := &pb.Transaction{
Version: req.Version,
From: req.From,
To: req.To,
Timestamp: req.Timestamp,
Data: req.Data,
Nonce: req.Nonce,
Signature: req.Signature,
Extra: req.Extra,
}
tx.TransactionHash = tx.Hash()
err := cbs.api.Broker().HandleTransaction(tx)
if err != nil {
return "", err
}
return tx.TransactionHash.Hex(), nil
}
func (cbs *ChainBrokerService) GetTransaction(ctx context.Context, req *pb.TransactionHashMsg) (*pb.GetTransactionResponse, error) {
hash := types.String2Hash(req.TxHash)
tx, err := cbs.api.Broker().GetTransaction(hash)
if err != nil {
return nil, err
}
meta, err := cbs.api.Broker().GetTransactionMeta(hash)
if err != nil {
return nil, err
}
return &pb.GetTransactionResponse{
Tx: tx,
TxMeta: meta,
}, nil
}