lbcutil/psbt/psbt.go
Adam Gibson e17c9730c4 PSBT BIP 174 implementation (#126)
Implements: PSBT struct, roles: creator, updater, signer, extractor.
Passing test vectors.
2019-12-19 15:20:22 -03:00

987 lines
27 KiB
Go

// Copyright (c) 2018 The btcsuite developers
// Use of this source code is governed by an ISC
// license that can be found in the LICENSE file.
// Package psbt is an implementation of Partially Signed Bitcoin
// Transactions (PSBT). The format is defined in BIP 174:
// https://github.com/bitcoin/bips/blob/master/bip-0174.mediawiki
package psbt
import (
"bytes"
"encoding/base64"
"encoding/binary"
"errors"
"io"
"sort"
"github.com/btcsuite/btcd/btcec"
"github.com/btcsuite/btcd/txscript"
"github.com/btcsuite/btcd/wire"
)
// BIP-174 aka PSBT defined values
// Key types are currently encoded with single bytes
type psbtKeyType = uint8
const psbtMagicLength = 5
var (
psbtMagic = [psbtMagicLength]byte{0x70,
0x73, 0x62, 0x74, 0xff, // = "psbt" + 0xff sep
}
)
// MaxPsbtValueLength is the size of the largest transaction serialization
// that could be passed in a NonWitnessUtxo field. This is definitely
//less than 4M.
const MaxPsbtValueLength = 4000000
// The below are the known key types as per the BIP.
// Unknown types may be accepted but will not be processed.
const (
// Global known key types
PsbtGlobalUnsignedTx psbtKeyType = 0
// TxIn section known key types
PsbtInNonWitnessUtxo psbtKeyType = 0
PsbtInWitnessUtxo psbtKeyType = 1
PsbtInPartialSig psbtKeyType = 2
PsbtInSighashType psbtKeyType = 3
PsbtInRedeemScript psbtKeyType = 4
PsbtInWitnessScript psbtKeyType = 5
PsbtInBip32Derivation psbtKeyType = 6
PsbtInFinalScriptSig psbtKeyType = 7
PsbtInFinalScriptWitness psbtKeyType = 8
// TxOut section known key types
PsbtOutRedeemScript psbtKeyType = 0
PsbtOutWitnessScript psbtKeyType = 1
PsbtOutBip32Derivation psbtKeyType = 2
)
var (
// ErrInvalidPsbtFormat is a generic error for any situation in which a
// provided Psbt serialization does not conform to the rules of BIP174.
ErrInvalidPsbtFormat = errors.New("Invalid PSBT serialization format")
// ErrDuplicateKey indicates that a passed Psbt serialization is invalid
// due to having the same key repeated in the same key-value pair.
ErrDuplicateKey = errors.New("Invalid Psbt due to duplicate key")
// ErrInvalidKeydata indicates that a key-value pair in the PSBT
// serialization contains data in the key which is not valid.
ErrInvalidKeydata = errors.New("Invalid key data")
// ErrInvalidMagicBytes indicates that a passed Psbt serialization is invalid
// due to having incorrect magic bytes.
ErrInvalidMagicBytes = errors.New("Invalid Psbt due to incorrect magic bytes")
// ErrInvalidRawTxSigned indicates that the raw serialized transaction in the
// global section of the passed Psbt serialization is invalid because it
// contains scriptSigs/witnesses (i.e. is fully or partially signed), which
// is not allowed by BIP174.
ErrInvalidRawTxSigned = errors.New("Invalid Psbt, raw transaction must " +
"be unsigned.")
// ErrInvalidPrevOutNonWitnessTransaction indicates that the transaction
// hash (i.e. SHA256^2) of the fully serialized previous transaction
// provided in the NonWitnessUtxo key-value field doesn't match the prevout
// hash in the UnsignedTx field in the PSBT itself.
ErrInvalidPrevOutNonWitnessTransaction = errors.New("Prevout hash does " +
"not match the provided non-witness utxo serialization")
// ErrInvalidSignatureForInput indicates that the signature the user is
// trying to append to the PSBT is invalid, either because it does
// not correspond to the previous transaction hash, or redeem script,
// or witness script.
// NOTE this does not include ECDSA signature checking.
ErrInvalidSignatureForInput = errors.New("Signature does not correspond " +
"to this input")
// ErrInputAlreadyFinalized indicates that the PSBT passed to a Finalizer
// already contains the finalized scriptSig or witness.
ErrInputAlreadyFinalized = errors.New("Cannot finalize PSBT, finalized " +
"scriptSig or scriptWitnes already exists")
// ErrIncompletePSBT indicates that the Extractor object
// was unable to successfully extract the passed Psbt struct because
// it is not complete
ErrIncompletePSBT = errors.New("PSBT cannot be extracted as it is " +
"incomplete")
// ErrNotFinalizable indicates that the PSBT struct does not have
// sufficient data (e.g. signatures) for finalization
ErrNotFinalizable = errors.New("PSBT is not finalizable")
// ErrInvalidSigHashFlags indicates that a signature added to the PSBT
// uses Sighash flags that are not in accordance with the requirement
// according to the entry in PsbtInSighashType, or otherwise not the
// default value (SIGHASH_ALL)
ErrInvalidSigHashFlags = errors.New("Invalid Sighash Flags")
// ErrUnsupportedScriptType indicates that the redeem script or
// scriptwitness given is not supported by this codebase, or is otherwise
// not valid.
ErrUnsupportedScriptType = errors.New("Unsupported script type")
)
func serializeKVpair(w io.Writer, key []byte, value []byte) error {
err := wire.WriteVarBytes(w, 0, key)
if err != nil {
return err
}
err = wire.WriteVarBytes(w, 0, value)
if err != nil {
return err
}
return nil
}
func serializeKVPairWithType(w io.Writer, kt psbtKeyType, keydata []byte,
value []byte) error {
if keydata == nil {
keydata = []byte{}
}
serializedKey := append([]byte{byte(kt)}, keydata...)
return serializeKVpair(w, serializedKey, value)
}
// getKey retrieves a single key - both the key type and the keydata
// (if present) from the stream and returns the key type as an integer,
// or -1 if the key was of zero length, which is used to indicate the
// presence of a separator byte which indicates the end of a given key-
// value pair list, and the keydata as a byte slice or nil if none is
// present.
func getKey(r io.Reader) (int, []byte, error) {
// For the key, we read the varint separately, instead of
// using the available ReadVarBytes, because we have a specific
// treatment of 0x00 here:
count, err := wire.ReadVarInt(r, 0)
if err != nil {
return -1, nil, ErrInvalidPsbtFormat
}
if count == 0 {
// separator indicates end of key-value pair list
return -1, nil, nil
}
// read count bytes, this is the key (including type and any data)
var keyintanddata = make([]byte, count)
if _, err := io.ReadFull(r, keyintanddata[:]); err != nil {
return -1, nil, err
}
keyType := int(string(keyintanddata)[0])
// Note that the second return value will usually be empty,
// since most keys contain no more than the key type byte.
if len(keyintanddata) == 1 {
return keyType, nil, nil
}
return keyType, keyintanddata[1:], nil
}
// readTxOut is a limited version of wire.readTxOut, because
// the latter is not exported.
func readTxOut(txout []byte) (*wire.TxOut, error) {
if len(txout) < 10 {
return nil, ErrInvalidPsbtFormat
}
valueSer := binary.LittleEndian.Uint64(txout[:8])
scriptPubKey := txout[9:]
return wire.NewTxOut(int64(valueSer), scriptPubKey), nil
}
// PartialSig encapsulate a (BTC public key, ECDSA signature)
// pair, note that the fields are stored as byte slices, not
// btcec.PublicKey or btcec.Signature (because manipulations will
// be with the former not the latter, here); compliance with consensus
// serialization is enforced with .checkValid()
type PartialSig struct {
PubKey []byte
Signature []byte
}
// PartialSigSorter implements sort.Interface.
type PartialSigSorter []*PartialSig
func (s PartialSigSorter) Len() int { return len(s) }
func (s PartialSigSorter) Swap(i, j int) { s[i], s[j] = s[j], s[i] }
func (s PartialSigSorter) Less(i, j int) bool {
return bytes.Compare(s[i].PubKey, s[j].PubKey) < 0
}
// validatePubkey checks if pubKey is *any* valid
// pubKey serialization in a Bitcoin context (compressed/uncomp. OK)
func validatePubkey(pubKey []byte) bool {
_, err := btcec.ParsePubKey(pubKey, btcec.S256())
if err != nil {
return false
}
return true
}
// validateSignature checks that the passed byte slice is a valid
// DER-encoded ECDSA signature, including the sighash flag.
// It does *not* of course validate the signature against any message
// or public key.
func validateSignature(sig []byte) bool {
_, err := btcec.ParseDERSignature(sig, btcec.S256())
if err != nil {
return false
}
return true
}
// See above notes (PartialSig, validatePubkey, validateSignature).
// NOTE update for Schnorr will be needed here if/when that activates.
func (ps *PartialSig) checkValid() bool {
return validatePubkey(ps.PubKey) && validateSignature(ps.Signature)
}
// Bip32Derivation encapsulates the data for the input and output
// Bip32Derivation key-value fields.
type Bip32Derivation struct {
PubKey []byte
MasterKeyFingerprint uint32
Bip32Path []uint32
}
// checkValid ensures that the PubKey in the Bip32Derivation
// struct is valid.
func (pb *Bip32Derivation) checkValid() bool {
return validatePubkey(pb.PubKey)
}
// Bip32Sorter implements sort.Interface.
type Bip32Sorter []*Bip32Derivation
func (s Bip32Sorter) Len() int { return len(s) }
func (s Bip32Sorter) Swap(i, j int) { s[i], s[j] = s[j], s[i] }
func (s Bip32Sorter) Less(i, j int) bool {
return bytes.Compare(s[i].PubKey, s[j].PubKey) < 0
}
// readBip32Derivation deserializes a byte slice containing
// chunks of 4 byte little endian encodings of uint32 values,
// the first of which is the masterkeyfingerprint and the remainder
// of which are the derivation path.
func readBip32Derivation(path []byte) (uint32, []uint32, error) {
if len(path)%4 != 0 || len(path)/4-1 < 1 {
return 0, nil, ErrInvalidPsbtFormat
}
masterKeyInt := binary.LittleEndian.Uint32(path[:4])
paths := make([]uint32, 0)
for i := 4; i < len(path); i += 4 {
paths = append(paths, binary.LittleEndian.Uint32(path[i:i+4]))
}
return masterKeyInt, paths, nil
}
// SerializeBIP32Derivation takes a master key fingerprint
// as defined in BIP32, along with a path specified as a list
// of uint32 values, and returns a bytestring specifying the derivation
// in the format required by BIP174:
// // master key fingerprint (4) || child index (4) || child index (4) || ...
func SerializeBIP32Derivation(masterKeyFingerprint uint32,
bip32Path []uint32) []byte {
derivationPath := make([]byte, 0, 4+4*len(bip32Path))
var masterKeyBytes [4]byte
binary.LittleEndian.PutUint32(masterKeyBytes[:], masterKeyFingerprint)
derivationPath = append(derivationPath, masterKeyBytes[:]...)
for _, path := range bip32Path {
var pathbytes [4]byte
binary.LittleEndian.PutUint32(pathbytes[:], path)
derivationPath = append(derivationPath, pathbytes[:]...)
}
return derivationPath
}
// Unknown is a struct encapsulating a key-value pair for which
// the key type is unknown by this package; these fields are allowed
// in both the 'Global' and the 'Input' section of a PSBT.
type Unknown struct {
Key []byte
Value []byte
}
// PInput is a struct encapsulating all the data that can be attached
// to any specific input of the PSBT.
type PInput struct {
NonWitnessUtxo *wire.MsgTx
WitnessUtxo *wire.TxOut
PartialSigs []*PartialSig
SighashType txscript.SigHashType
RedeemScript []byte
WitnessScript []byte
Bip32Derivation []*Bip32Derivation
FinalScriptSig []byte
FinalScriptWitness []byte
Unknowns []*Unknown
}
// NewPsbtInput creates an instance of PsbtInput given either a
// nonWitnessUtxo or a witnessUtxo.
// NOTE only one of the two arguments should be specified, with the other
// being `nil`; otherwise the created PsbtInput object will fail IsSane()
// checks and will not be usable.
func NewPsbtInput(nonWitnessUtxo *wire.MsgTx,
witnessUtxo *wire.TxOut) *PInput {
return &PInput{
NonWitnessUtxo: nonWitnessUtxo,
WitnessUtxo: witnessUtxo,
PartialSigs: []*PartialSig{},
SighashType: 0,
RedeemScript: nil,
WitnessScript: nil,
Bip32Derivation: []*Bip32Derivation{},
FinalScriptSig: nil,
FinalScriptWitness: nil,
Unknowns: nil,
}
}
// IsSane returns true only if there are no conflicting
// values in the Psbt PInput. It checks that witness and non-witness
// utxo entries do not both exist, and that witnessScript entries are only
// added to witness inputs.
func (pi *PInput) IsSane() bool {
if pi.NonWitnessUtxo != nil && pi.WitnessUtxo != nil {
return false
}
if pi.WitnessUtxo == nil && pi.WitnessScript != nil {
return false
}
if pi.WitnessUtxo == nil && pi.FinalScriptWitness != nil {
return false
}
return true
}
func (pi *PInput) deserialize(r io.Reader) error {
for {
keyint, keydata, err := getKey(r)
if err != nil {
return err
}
if keyint == -1 {
// Reached separator byte
break
}
value, err := wire.ReadVarBytes(r, 0, MaxPsbtValueLength,
"PSBT value")
if err != nil {
return err
}
switch uint8(keyint) {
case PsbtInNonWitnessUtxo:
if pi.NonWitnessUtxo != nil {
return ErrDuplicateKey
}
if keydata != nil {
return ErrInvalidKeydata
}
tx := wire.NewMsgTx(2)
if err := tx.Deserialize(bytes.NewReader(value)); err != nil {
return err
}
pi.NonWitnessUtxo = tx
case PsbtInWitnessUtxo:
if pi.WitnessUtxo != nil {
return ErrDuplicateKey
}
if keydata != nil {
return ErrInvalidKeydata
}
txout, err := readTxOut(value)
if err != nil {
return err
}
pi.WitnessUtxo = txout
case PsbtInPartialSig:
newPartialSig := PartialSig{PubKey: keydata,
Signature: value}
if !newPartialSig.checkValid() {
return ErrInvalidPsbtFormat
}
// Duplicate keys are not allowed
for _, x := range pi.PartialSigs {
if bytes.Equal(x.PubKey, newPartialSig.PubKey) {
return ErrDuplicateKey
}
}
pi.PartialSigs = append(pi.PartialSigs, &newPartialSig)
case PsbtInSighashType:
if pi.SighashType != 0 {
return ErrDuplicateKey
}
if keydata != nil {
return ErrInvalidKeydata
}
shtype := txscript.SigHashType(binary.LittleEndian.Uint32(value))
pi.SighashType = shtype
case PsbtInRedeemScript:
if pi.RedeemScript != nil {
return ErrDuplicateKey
}
if keydata != nil {
return ErrInvalidKeydata
}
pi.RedeemScript = value
case PsbtInWitnessScript:
if pi.WitnessScript != nil {
return ErrDuplicateKey
}
if keydata != nil {
return ErrInvalidKeydata
}
pi.WitnessScript = value
case PsbtInBip32Derivation:
if !validatePubkey(keydata) {
return ErrInvalidPsbtFormat
}
master, derivationPath, err := readBip32Derivation(value)
if err != nil {
return err
}
// Duplicate keys are not allowed
for _, x := range pi.Bip32Derivation {
if bytes.Equal(x.PubKey, keydata) {
return ErrDuplicateKey
}
}
pi.Bip32Derivation = append(pi.Bip32Derivation,
&Bip32Derivation{
PubKey: keydata,
MasterKeyFingerprint: master,
Bip32Path: derivationPath,
})
case PsbtInFinalScriptSig:
if pi.FinalScriptSig != nil {
return ErrDuplicateKey
}
if keydata != nil {
return ErrInvalidKeydata
}
pi.FinalScriptSig = value
case PsbtInFinalScriptWitness:
if pi.FinalScriptWitness != nil {
return ErrDuplicateKey
}
if keydata != nil {
return ErrInvalidKeydata
}
pi.FinalScriptWitness = value
default:
keyintanddata := []byte{byte(keyint)}
keyintanddata = append(keyintanddata, keydata...)
newUnknown := &Unknown{
Key: keyintanddata,
Value: value,
}
// Duplicate key+keydata are not allowed
for _, x := range pi.Unknowns {
if bytes.Equal(x.Key, newUnknown.Key) && bytes.Equal(x.Value,
newUnknown.Value) {
return ErrDuplicateKey
}
}
pi.Unknowns = append(pi.Unknowns, newUnknown)
}
}
return nil
}
func (pi *PInput) serialize(w io.Writer) error {
if !pi.IsSane() {
return ErrInvalidPsbtFormat
}
if pi.NonWitnessUtxo != nil {
var buf bytes.Buffer
err := pi.NonWitnessUtxo.Serialize(&buf)
if err != nil {
return err
}
err = serializeKVPairWithType(w, PsbtInNonWitnessUtxo, nil,
buf.Bytes())
if err != nil {
return err
}
}
if pi.WitnessUtxo != nil {
var buf bytes.Buffer
err := wire.WriteTxOut(&buf, 0, 0, pi.WitnessUtxo)
if err != nil {
return err
}
err = serializeKVPairWithType(w, PsbtInWitnessUtxo, nil, buf.Bytes())
if err != nil {
return err
}
}
if pi.FinalScriptSig == nil && pi.FinalScriptWitness == nil {
sort.Sort(PartialSigSorter(pi.PartialSigs))
for _, ps := range pi.PartialSigs {
err := serializeKVPairWithType(w, PsbtInPartialSig, ps.PubKey,
ps.Signature)
if err != nil {
return err
}
}
if pi.SighashType != 0 {
var shtBytes [4]byte
binary.LittleEndian.PutUint32(shtBytes[:],
uint32(pi.SighashType))
err := serializeKVPairWithType(w, PsbtInSighashType, nil,
shtBytes[:])
if err != nil {
return err
}
}
if pi.RedeemScript != nil {
err := serializeKVPairWithType(w, PsbtInRedeemScript, nil,
pi.RedeemScript)
if err != nil {
return err
}
}
if pi.WitnessScript != nil {
err := serializeKVPairWithType(w, PsbtInWitnessScript, nil,
pi.WitnessScript)
if err != nil {
return err
}
}
sort.Sort(Bip32Sorter(pi.Bip32Derivation))
for _, kd := range pi.Bip32Derivation {
err := serializeKVPairWithType(w, PsbtInBip32Derivation,
kd.PubKey,
SerializeBIP32Derivation(kd.MasterKeyFingerprint,
kd.Bip32Path))
if err != nil {
return err
}
}
}
if pi.FinalScriptSig != nil {
err := serializeKVPairWithType(w, PsbtInFinalScriptSig, nil,
pi.FinalScriptSig)
if err != nil {
return err
}
}
if pi.FinalScriptWitness != nil {
err := serializeKVPairWithType(w, PsbtInFinalScriptWitness, nil,
pi.FinalScriptWitness)
if err != nil {
return err
}
}
// Unknown is a special case; we don't have a key type, only
// a key and a value field
for _, kv := range pi.Unknowns {
err := serializeKVpair(w, kv.Key, kv.Value)
if err != nil {
return err
}
}
return nil
}
// POutput is a struct encapsulating all the data that can be attached
// to any specific output of the PSBT.
type POutput struct {
RedeemScript []byte
WitnessScript []byte
Bip32Derivation []*Bip32Derivation
}
// NewPsbtOutput creates an instance of PsbtOutput; the three parameters
// redeemScript, witnessScript and Bip32Derivation are all allowed to be
// `nil`.
func NewPsbtOutput(redeemScript []byte, witnessScript []byte,
bip32Derivation []*Bip32Derivation) *POutput {
return &POutput{
RedeemScript: redeemScript,
WitnessScript: witnessScript,
Bip32Derivation: bip32Derivation,
}
}
func (po *POutput) deserialize(r io.Reader) error {
for {
keyint, keydata, err := getKey(r)
if err != nil {
return err
}
if keyint == -1 {
// Reached separator byte
break
}
value, err := wire.ReadVarBytes(r, 0, MaxPsbtValueLength,
"PSBT value")
if err != nil {
return err
}
switch uint8(keyint) {
case PsbtOutRedeemScript:
if po.RedeemScript != nil {
return ErrDuplicateKey
}
if keydata != nil {
return ErrInvalidKeydata
}
po.RedeemScript = value
case PsbtOutWitnessScript:
if po.WitnessScript != nil {
return ErrDuplicateKey
}
if keydata != nil {
return ErrInvalidKeydata
}
po.WitnessScript = value
case PsbtOutBip32Derivation:
if !validatePubkey(keydata) {
return ErrInvalidKeydata
}
master, derivationPath, err := readBip32Derivation(value)
if err != nil {
return err
}
// Duplicate keys are not allowed
for _, x := range po.Bip32Derivation {
if bytes.Equal(x.PubKey, keydata) {
return ErrDuplicateKey
}
}
po.Bip32Derivation = append(po.Bip32Derivation,
&Bip32Derivation{
PubKey: keydata,
MasterKeyFingerprint: master,
Bip32Path: derivationPath,
})
default:
// unknown type is allowed for inputs but not outputs
return ErrInvalidPsbtFormat
}
}
return nil
}
func (po *POutput) serialize(w io.Writer) error {
if po.RedeemScript != nil {
err := serializeKVPairWithType(w, PsbtOutRedeemScript, nil,
po.RedeemScript)
if err != nil {
return err
}
}
if po.WitnessScript != nil {
err := serializeKVPairWithType(w, PsbtOutWitnessScript, nil,
po.WitnessScript)
if err != nil {
return err
}
}
sort.Sort(Bip32Sorter(po.Bip32Derivation))
for _, kd := range po.Bip32Derivation {
err := serializeKVPairWithType(w, PsbtOutBip32Derivation,
kd.PubKey,
SerializeBIP32Derivation(kd.MasterKeyFingerprint,
kd.Bip32Path))
if err != nil {
return err
}
}
return nil
}
// Psbt is a set of 1 + N + M key-value pair lists, 1 global,
// defining the unsigned transaction structure with N inputs and M outputs.
// These key-value pairs can contain scripts, signatures,
// key derivations and other transaction-defining data.
type Psbt struct {
UnsignedTx *wire.MsgTx // Deserialization of unsigned tx
Inputs []PInput
Outputs []POutput
Unknowns []Unknown // Data of unknown type at global scope
}
// validateUnsignedTx returns true if the transaction is unsigned.
// Note that more basic sanity requirements,
// such as the presence of inputs and outputs, is implicitly
// checked in the call to MsgTx.Deserialize()
func validateUnsignedTX(tx *wire.MsgTx) bool {
for _, tin := range tx.TxIn {
if len(tin.SignatureScript) != 0 || len(tin.Witness) != 0 {
return false
}
}
return true
}
// NewPsbtFromUnsignedTx creates a new Psbt struct, without
// any signatures (i.e. only the global section is non-empty).
func NewPsbtFromUnsignedTx(tx *wire.MsgTx) (*Psbt, error) {
if !validateUnsignedTX(tx) {
return nil, ErrInvalidRawTxSigned
}
inSlice := make([]PInput, len(tx.TxIn))
outSlice := make([]POutput, len(tx.TxOut))
unknownSlice := make([]Unknown, 0)
retPsbt := Psbt{
UnsignedTx: tx,
Inputs: inSlice,
Outputs: outSlice,
Unknowns: unknownSlice,
}
return &retPsbt, nil
}
// NewPsbt returns a new instance of a Psbt struct created
// by reading from a byte slice. If the format is invalid, an error
// is returned. If the argument b64 is true, the passed byte slice
// is decoded from base64 encoding before processing.
// NOTE To create a Psbt from one's own data, rather than reading
// in a serialization from a counterparty, one should use a psbt.Creator.
func NewPsbt(psbtBytes []byte, b64 bool) (*Psbt, error) {
var err error
if b64 {
decoded := make([]byte, base64.StdEncoding.DecodedLen(len(psbtBytes)))
_, err = base64.StdEncoding.Decode(decoded, psbtBytes)
if err != nil {
return nil, err
}
psbtBytes = decoded
}
r := bytes.NewReader(psbtBytes)
// The Psbt struct does not store the fixed magic bytes,
// but they must be present or the serialization must
// be explicitly rejected.
var magic [5]byte
if _, err = io.ReadFull(r, magic[:]); err != nil {
return nil, err
}
if magic != psbtMagic {
return nil, ErrInvalidMagicBytes
}
// Next we parse the GLOBAL section.
// There is currently only 1 known key type, UnsignedTx.
// We insist this exists first; unknowns are allowed, but
// only after.
keyint, keydata, err := getKey(r)
if err != nil {
return nil, err
}
if uint8(keyint) != PsbtGlobalUnsignedTx || keydata != nil {
return nil, ErrInvalidPsbtFormat
}
value, err := wire.ReadVarBytes(r, 0, MaxPsbtValueLength,
"PSBT value")
if err != nil {
return nil, err
}
// Attempt to deserialize the unsigned transaction.
msgTx := wire.NewMsgTx(2)
err = msgTx.Deserialize(bytes.NewReader(value))
if err != nil {
return nil, err
}
if !validateUnsignedTX(msgTx) {
return nil, ErrInvalidRawTxSigned
}
// parse any unknowns that may be present, break at separator
unknownSlice := make([]Unknown, 0)
for {
keyint, keydata, err := getKey(r)
if err != nil {
return nil, ErrInvalidPsbtFormat
}
if keyint == -1 {
break
}
value, err := wire.ReadVarBytes(r, 0, MaxPsbtValueLength,
"PSBT value")
if err != nil {
return nil, err
}
keyintanddata := []byte{byte(keyint)}
keyintanddata = append(keyintanddata, keydata...)
newUnknown := Unknown{
Key: keyintanddata,
Value: value,
}
unknownSlice = append(unknownSlice, newUnknown)
}
// Next we parse the INPUT section
inSlice := make([]PInput, len(msgTx.TxIn))
for i := range msgTx.TxIn {
input := PInput{}
err = input.deserialize(r)
if err != nil {
return nil, err
}
inSlice[i] = input
}
//Next we parse the OUTPUT section
outSlice := make([]POutput, len(msgTx.TxOut))
for i := range msgTx.TxOut {
output := POutput{}
err = output.deserialize(r)
if err != nil {
return nil, err
}
outSlice[i] = output
}
// Populate the new Psbt object
newPsbt := Psbt{
UnsignedTx: msgTx,
Inputs: inSlice,
Outputs: outSlice,
Unknowns: unknownSlice,
}
// Extended sanity checking is applied here
// to make sure the externally-passed Psbt follows
// all the rules.
if err = newPsbt.SanityCheck(); err != nil {
return nil, err
}
return &newPsbt, nil
}
// Serialize creates a binary serialization of the referenced
// Psbt struct with lexicographical ordering (by key) of the subsections
func (p *Psbt) Serialize() ([]byte, error) {
serPsbt := []byte{}
serPsbt = append(serPsbt, psbtMagic[:]...)
// Create serialization of unsignedtx
serializedTx := bytes.NewBuffer(make([]byte, 0,
p.UnsignedTx.SerializeSize()))
if err := p.UnsignedTx.Serialize(serializedTx); err != nil {
return nil, err
}
var buf bytes.Buffer
err := serializeKVPairWithType(&buf, PsbtGlobalUnsignedTx,
nil, serializedTx.Bytes())
if err != nil {
return nil, err
}
serPsbt = append(serPsbt, buf.Bytes()...)
serPsbt = append(serPsbt, 0x00)
for _, pInput := range p.Inputs {
var buf bytes.Buffer
err := pInput.serialize(&buf)
if err != nil {
return nil, err
}
serPsbt = append(serPsbt, buf.Bytes()...)
serPsbt = append(serPsbt, 0x00)
}
for _, pOutput := range p.Outputs {
var buf bytes.Buffer
err := pOutput.serialize(&buf)
if err != nil {
return nil, err
}
serPsbt = append(serPsbt, buf.Bytes()...)
serPsbt = append(serPsbt, 0x00)
}
return serPsbt, nil
}
// B64Encode returns the base64 encoding of the serialization of
// the current PSBT, or an error if the encoding fails.
func (p *Psbt) B64Encode() (string, error) {
raw, err := p.Serialize()
if err != nil {
return "", err
}
return base64.StdEncoding.EncodeToString(raw), nil
}
// IsComplete returns true only if all of the inputs are
// finalized; this is particularly important in that it decides
// whether the final extraction to a network serialized signed
// transaction will be possible.
func (p *Psbt) IsComplete() bool {
for i := 0; i < len(p.UnsignedTx.TxIn); i++ {
if !isFinalized(p, i) {
return false
}
}
return true
}
// SanityCheck checks conditions on a PSBT to ensure that it obeys the
// rules of BIP174, and returns true if so, false if not.
func (p *Psbt) SanityCheck() error {
if !validateUnsignedTX(p.UnsignedTx) {
return ErrInvalidRawTxSigned
}
for _, tin := range p.Inputs {
if !tin.IsSane() {
return ErrInvalidPsbtFormat
}
}
return nil
}