OSDN Git Service

Change spv wallet send tx
[bytom/bytom-spv.git] / blockchain / txbuilder / finalize.go
1 package txbuilder
2
3 import (
4         "bytes"
5         "context"
6
7         "github.com/bytom/errors"
8         "github.com/bytom/protocol/bc/types"
9         "github.com/bytom/protocol/vm"
10 )
11
12 var (
13         // ErrRejected means the network rejected a tx (as a double-spend)
14         ErrRejected = errors.New("transaction rejected")
15         // ErrMissingRawTx means missing transaction
16         ErrMissingRawTx = errors.New("missing raw tx")
17         // ErrBadInstructionCount means too many signing instructions compare with inputs
18         ErrBadInstructionCount = errors.New("too many signing instructions in template")
19 )
20
21 // FinalizeTx validates a transaction signature template,
22 // assembles a fully signed tx, and stores the effects of
23 // its changes on the UTXO set.
24 func FinalizeTx(ctx context.Context, txCh chan *types.Tx,tx *types.Tx) error {
25         if err := checkTxSighashCommitment(tx); err != nil {
26                 return err
27         }
28
29         // This part is use for prevent tx size  is 0
30         data, err := tx.TxData.MarshalText()
31         if err != nil {
32                 return err
33         }
34         tx.TxData.SerializedSize = uint64(len(data))
35         tx.Tx.SerializedSize = uint64(len(data))
36
37         txCh <- tx
38
39         return errors.Wrap(err)
40 }
41
42 var (
43         // ErrNoTxSighashCommitment is returned when no input commits to the
44         // complete transaction.
45         // To permit idempotence of transaction submission, we require at
46         // least one input to commit to the complete transaction (what you get
47         // when you build a transaction with allow_additional_actions=false).
48         ErrNoTxSighashCommitment = errors.New("no commitment to tx sighash")
49
50         // ErrNoTxSighashAttempt is returned when there was no attempt made to sign
51         // this transaction.
52         ErrNoTxSighashAttempt = errors.New("no tx sighash attempted")
53
54         // ErrTxSignatureFailure is returned when there was an attempt to sign this
55         // transaction, but it failed.
56         ErrTxSignatureFailure = errors.New("tx signature was attempted but failed")
57 )
58
59 func checkTxSighashCommitment(tx *types.Tx) error {
60         // TODO: this is the local sender check rules, we might don't need it due to the rule is difference
61         return nil
62         var lastError error
63
64         for i, inp := range tx.Inputs {
65                 var args [][]byte
66                 switch t := inp.TypedInput.(type) {
67                 case *types.SpendInput:
68                         args = t.Arguments
69                 case *types.IssuanceInput:
70                         args = t.Arguments
71                 }
72                 // Note: These numbers will need to change if more args are added such that the minimum length changes
73                 switch {
74                 // A conforming arguments list contains
75                 // [... arg1 arg2 ... argN N sig1 sig2 ... sigM prog]
76                 // The args are the opaque arguments to prog. In the case where
77                 // N is 0 (prog takes no args), and assuming there must be at
78                 // least one signature, args has a minimum length of 3.
79                 case len(args) == 0:
80                         lastError = ErrNoTxSighashAttempt
81                         continue
82                 case len(args) < 3:
83                         lastError = ErrTxSignatureFailure
84                         continue
85                 }
86                 lastError = ErrNoTxSighashCommitment
87                 prog := args[len(args)-1]
88                 if len(prog) != 35 {
89                         continue
90                 }
91                 if prog[0] != byte(vm.OP_DATA_32) {
92                         continue
93                 }
94                 if !bytes.Equal(prog[33:], []byte{byte(vm.OP_TXSIGHASH), byte(vm.OP_EQUAL)}) {
95                         continue
96                 }
97                 h := tx.SigHash(uint32(i))
98                 if !bytes.Equal(h.Bytes(), prog[1:33]) {
99                         continue
100                 }
101                 // At least one input passes commitment checks
102                 return nil
103         }
104
105         return lastError
106 }
107
108 // RemoteGenerator implements the Submitter interface and submits the
109 // transaction to a remote generator.
110 // TODO(jackson): This implementation maybe belongs elsewhere.
111 /*type RemoteGenerator struct {
112         Peer *rpc.Client
113 }
114
115 func (rg *RemoteGenerator) Submit(ctx context.Context, tx *types.Tx) error {
116         err := rg.Peer.Call(ctx, "/rpc/submit", tx, nil)
117         err = errors.Wrap(err, "generator transaction notice")
118         return err
119 }
120 */