OSDN Git Service

versoin1.1.9 (#594)
[bytom/vapor.git] / blockchain / txbuilder / rawtxsig_witness.go
1 package txbuilder
2
3 import (
4         "context"
5         "encoding/json"
6
7         log "github.com/sirupsen/logrus"
8
9         chainjson "github.com/bytom/vapor/encoding/json"
10 )
11
12 // TODO(bobg): most of the code here is duplicated from
13 // signature_witness.go and needs refactoring.
14
15 // RawTxSigWitness is like SignatureWitness but doesn't involve
16 // signature programs.
17 type RawTxSigWitness struct {
18         Quorum int                  `json:"quorum"`
19         Keys   []keyID              `json:"keys"`
20         Sigs   []chainjson.HexBytes `json:"signatures"`
21 }
22
23 func (sw *RawTxSigWitness) sign(ctx context.Context, tpl *Template, index uint32, auth string, signFn SignFunc) error {
24         if len(sw.Sigs) < len(sw.Keys) {
25                 // Each key in sw.Keys may produce a signature in sw.Sigs. Make
26                 // sure there are enough slots in sw.Sigs and that we preserve any
27                 // sigs already present.
28                 newSigs := make([]chainjson.HexBytes, len(sw.Keys))
29                 copy(newSigs, sw.Sigs)
30                 sw.Sigs = newSigs
31         }
32         for i, keyID := range sw.Keys {
33                 if len(sw.Sigs[i]) > 0 {
34                         // Already have a signature for this key
35                         continue
36                 }
37                 path := make([][]byte, len(keyID.DerivationPath))
38                 for i, p := range keyID.DerivationPath {
39                         path[i] = p
40                 }
41                 sigBytes, err := signFn(ctx, keyID.XPub, path, tpl.Hash(index).Byte32(), auth)
42                 if err != nil {
43                         log.WithFields(log.Fields{"module": logModule, "err": err}).Warningf("computing signature %d", i)
44                         continue
45                 }
46
47                 // This break is ordered to avoid signing transaction successfully only once for a multiple-sign account
48                 // that consist of different keys by the same password. Exit immediately when the signature is success,
49                 // it means that only one signature will be successful in the loop for this multiple-sign account.
50                 sw.Sigs[i] = sigBytes
51                 break
52         }
53         return nil
54 }
55
56 func (sw RawTxSigWitness) materialize(args *[][]byte) error {
57         var nsigs int
58         for i := 0; i < len(sw.Sigs) && nsigs < sw.Quorum; i++ {
59                 if len(sw.Sigs[i]) > 0 {
60                         *args = append(*args, sw.Sigs[i])
61                         nsigs++
62                 }
63         }
64         return nil
65 }
66
67 // MarshalJSON convert struct to json
68 func (sw RawTxSigWitness) MarshalJSON() ([]byte, error) {
69         obj := struct {
70                 Type   string               `json:"type"`
71                 Quorum int                  `json:"quorum"`
72                 Keys   []keyID              `json:"keys"`
73                 Sigs   []chainjson.HexBytes `json:"signatures"`
74         }{
75                 Type:   "raw_tx_signature",
76                 Quorum: sw.Quorum,
77                 Keys:   sw.Keys,
78                 Sigs:   sw.Sigs,
79         }
80         return json.Marshal(obj)
81 }