2020-03-29 21:32:01 +08:00
|
|
|
package grpc
|
|
|
|
|
|
|
|
import (
|
|
|
|
"context"
|
|
|
|
"fmt"
|
|
|
|
"time"
|
|
|
|
|
2020-09-30 19:19:38 +08:00
|
|
|
"github.com/meshplus/bitxhub-kit/crypto"
|
|
|
|
"github.com/meshplus/bitxhub-kit/crypto/asym"
|
2020-03-29 21:32:01 +08:00
|
|
|
"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.
|
2020-10-21 15:59:09 +08:00
|
|
|
func (cbs *ChainBrokerService) SendTransaction(ctx context.Context, tx *pb.Transaction) (*pb.TransactionHashMsg, error) {
|
2020-11-10 19:53:39 +08:00
|
|
|
err := cbs.api.Broker().OrderReady()
|
|
|
|
if err != nil {
|
|
|
|
return nil, fmt.Errorf("the system is temporarily unavailable, err: %s", err.Error())
|
2020-03-29 21:32:01 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
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
|
|
|
|
}
|
|
|
|
|
2020-10-21 15:59:09 +08:00
|
|
|
func (cbs *ChainBrokerService) SendView(_ context.Context, tx *pb.Transaction) (*pb.Receipt, error) {
|
2020-07-13 20:40:10 +08:00
|
|
|
if err := cbs.checkTransaction(tx); err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
result, err := cbs.sendView(tx)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
2020-07-16 16:24:10 +08:00
|
|
|
return result, nil
|
2020-07-13 20:40:10 +08:00
|
|
|
}
|
|
|
|
|
2020-10-21 15:59:09 +08:00
|
|
|
func (cbs *ChainBrokerService) checkTransaction(tx *pb.Transaction) error {
|
2020-10-27 17:24:02 +08:00
|
|
|
if tx.Payload == nil && tx.IBTP == nil {
|
|
|
|
return fmt.Errorf("tx payload and ibtp can't both be nil")
|
2020-03-29 21:32:01 +08:00
|
|
|
}
|
2020-10-23 15:29:47 +08:00
|
|
|
if tx.From == nil {
|
|
|
|
return fmt.Errorf("tx from address is nil")
|
|
|
|
}
|
|
|
|
if tx.To == nil {
|
|
|
|
tx.To = &types.Address{}
|
|
|
|
}
|
2020-03-29 21:32:01 +08:00
|
|
|
|
2020-10-21 15:59:09 +08:00
|
|
|
emptyAddress := &types.Address{}
|
2020-10-21 23:46:21 +08:00
|
|
|
if tx.From.String() == emptyAddress.String() {
|
2020-03-29 21:32:01 +08:00
|
|
|
return fmt.Errorf("from can't be empty")
|
|
|
|
}
|
|
|
|
|
2020-10-21 23:46:21 +08:00
|
|
|
if tx.From.String() == tx.To.String() {
|
2020-03-29 21:32:01 +08:00
|
|
|
return fmt.Errorf("from can`t be the same as to")
|
|
|
|
}
|
|
|
|
|
2020-10-21 23:46:21 +08:00
|
|
|
if tx.To.String() == emptyAddress.String() && len(tx.Payload) == 0 {
|
2020-03-29 21:32:01 +08:00
|
|
|
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
|
|
|
|
}
|
|
|
|
|
2020-10-21 15:59:09 +08:00
|
|
|
func (cbs *ChainBrokerService) sendTransaction(tx *pb.Transaction) (string, error) {
|
2020-10-21 23:46:21 +08:00
|
|
|
tx.TransactionHash = tx.Hash()
|
|
|
|
ok, _ := asym.Verify(crypto.Secp256k1, tx.Signature, tx.SignHash().Bytes(), *tx.From)
|
2020-09-30 19:19:38 +08:00
|
|
|
if !ok {
|
|
|
|
return "", fmt.Errorf("invalid signature")
|
|
|
|
}
|
2020-03-29 21:32:01 +08:00
|
|
|
err := cbs.api.Broker().HandleTransaction(tx)
|
|
|
|
if err != nil {
|
|
|
|
return "", err
|
|
|
|
}
|
|
|
|
|
2020-10-21 23:46:21 +08:00
|
|
|
return tx.TransactionHash.String(), nil
|
2020-03-29 21:32:01 +08:00
|
|
|
}
|
|
|
|
|
2020-10-21 15:59:09 +08:00
|
|
|
func (cbs *ChainBrokerService) sendView(tx *pb.Transaction) (*pb.Receipt, error) {
|
2020-07-13 20:40:10 +08:00
|
|
|
result, err := cbs.api.Broker().HandleView(tx)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
return result, nil
|
|
|
|
}
|
|
|
|
|
2020-03-29 21:32:01 +08:00
|
|
|
func (cbs *ChainBrokerService) GetTransaction(ctx context.Context, req *pb.TransactionHashMsg) (*pb.GetTransactionResponse, error) {
|
2020-10-21 23:46:21 +08:00
|
|
|
hash := types.NewHashByStr(req.TxHash)
|
2020-10-23 15:29:47 +08:00
|
|
|
if hash == nil {
|
|
|
|
return nil, fmt.Errorf("invalid format of tx hash for querying transaction")
|
|
|
|
}
|
2020-10-22 13:49:05 +08:00
|
|
|
tx, err := cbs.api.Broker().GetTransaction(hash)
|
2020-03-29 21:32:01 +08:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
2020-10-22 13:49:05 +08:00
|
|
|
meta, err := cbs.api.Broker().GetTransactionMeta(hash)
|
2020-03-29 21:32:01 +08:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
return &pb.GetTransactionResponse{
|
|
|
|
Tx: tx,
|
|
|
|
TxMeta: meta,
|
|
|
|
}, nil
|
|
|
|
}
|