OSDN Git Service

Merge pull request #41 from Bytom/dev
[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         "github.com/vapor/crypto/ed25519/chainkd"
10         chainjson "github.com/vapor/encoding/json"
11 )
12
13 // TODO(bobg): most of the code here is duplicated from
14 // signature_witness.go and needs refactoring.
15
16 // RawTxSigWitness is like SignatureWitness but doesn't involve
17 // signature programs.
18 type RawTxSigWitness struct {
19         Quorum int                  `json:"quorum"`
20         Keys   []keyID              `json:"keys"`
21         Sigs   []chainjson.HexBytes `json:"signatures"`
22 }
23
24 func (sw *RawTxSigWitness) sign(ctx context.Context, tpl *Template, index uint32, auth string, signFn SignFunc) error {
25         if len(sw.Sigs) < len(sw.Keys) {
26                 // Each key in sw.Keys may produce a signature in sw.Sigs. Make
27                 // sure there are enough slots in sw.Sigs and that we preserve any
28                 // sigs already present.
29                 newSigs := make([]chainjson.HexBytes, len(sw.Keys))
30                 copy(newSigs, sw.Sigs)
31                 sw.Sigs = newSigs
32         }
33         for i, keyID := range sw.Keys {
34                 if len(sw.Sigs[i]) > 0 {
35                         // Already have a signature for this key
36                         continue
37                 }
38                 path := make([][]byte, len(keyID.DerivationPath))
39                 for i, p := range keyID.DerivationPath {
40                         path[i] = p
41                 }
42                 sigBytes, err := signFn(ctx, keyID.XPub, path, tpl.Hash(index).Byte32(), auth)
43                 if err != nil {
44                         log.WithField("err", err).Warningf("computing signature %d", i)
45                         continue
46                 }
47
48                 // This break is ordered to avoid signing transaction successfully only once for a multiple-sign account
49                 // that consist of different keys by the same password. Exit immediately when the signature is success,
50                 // it means that only one signature will be successful in the loop for this multiple-sign account.
51                 sw.Sigs[i] = sigBytes
52                 break
53         }
54         return nil
55 }
56
57 func (sw *RawTxSigWitness) Sign(tpl *Template, index uint32, xprv chainkd.XPrv) error {
58         if len(sw.Sigs) < len(sw.Keys) {
59                 // Each key in sw.Keys may produce a signature in sw.Sigs. Make
60                 // sure there are enough slots in sw.Sigs and that we preserve any
61                 // sigs already present.
62                 newSigs := make([]chainjson.HexBytes, len(sw.Keys))
63                 copy(newSigs, sw.Sigs)
64                 sw.Sigs = newSigs
65         }
66         for i, keyID := range sw.Keys {
67                 if len(sw.Sigs[i]) > 0 {
68                         // Already have a signature for this key
69                         continue
70                 }
71                 if keyID.XPub.String() != xprv.XPub().String() {
72                         continue
73                 }
74                 data := tpl.Hash(index).Byte32()
75                 sigBytes := xprv.Sign(data[:])
76                 // This break is ordered to avoid signing transaction successfully only once for a multiple-sign account
77                 // that consist of different keys by the same password. Exit immediately when the signature is success,
78                 // it means that only one signature will be successful in the loop for this multiple-sign account.
79                 sw.Sigs[i] = sigBytes
80                 break
81         }
82         return nil
83 }
84
85 func (sw RawTxSigWitness) Materialize(args *[][]byte) error {
86         var nsigs int
87         for i := 0; i < len(sw.Sigs) && nsigs < sw.Quorum; i++ {
88                 if len(sw.Sigs[i]) > 0 {
89                         *args = append(*args, sw.Sigs[i])
90                         nsigs++
91                 }
92         }
93         return nil
94 }
95
96 // MarshalJSON convert struct to json
97 func (sw RawTxSigWitness) MarshalJSON() ([]byte, error) {
98         obj := struct {
99                 Type   string               `json:"type"`
100                 Quorum int                  `json:"quorum"`
101                 Keys   []keyID              `json:"keys"`
102                 Sigs   []chainjson.HexBytes `json:"signatures"`
103         }{
104                 Type:   "raw_tx_signature",
105                 Quorum: sw.Quorum,
106                 Keys:   sw.Keys,
107                 Sigs:   sw.Sigs,
108         }
109         return json.Marshal(obj)
110 }