github.com/Bytom/bytom@v1.1.2-0.20210127130405-ae40204c0b09/blockchain/txbuilder/rawtxsig_witness.go (about)

     1  package txbuilder
     2  
     3  import (
     4  	"context"
     5  	"encoding/json"
     6  
     7  	log "github.com/sirupsen/logrus"
     8  
     9  	chainjson "github.com/bytom/bytom/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  }