psbt: rename psbt.Psbt to psbt.Packet, rename existing constructors

This commit is contained in:
Olaoluwa Osuntokun 2020-01-15 17:43:16 -08:00
parent 014f58c55d
commit 3385fba2f2

View file

@ -10,14 +10,10 @@ package psbt
import ( import (
"bytes" "bytes"
"encoding/base64" "encoding/base64"
"encoding/binary"
"errors" "errors"
"io" "io"
"sort"
"github.com/btcsuite/btcd/btcec"
"github.com/btcsuite/btcd/txscript"
"github.com/btcsuite/btcd/wire" "github.com/btcsuite/btcd/wire"
) )
@ -112,38 +108,42 @@ type Unknown struct {
Value []byte Value []byte
} }
// Packet is the actual psbt repreesntation. It is a 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 Packet struct {
// Psbt is a set of 1 + N + M key-value pair lists, 1 global, // UnsignedTx is the decoded unsigned transaction for this PSBT.
// 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 UnsignedTx *wire.MsgTx // Deserialization of unsigned tx
Inputs []PInput
Outputs []POutput // Inputs contains all the information needed to properly sign this
Unknowns []Unknown // Data of unknown type at global scope // target input within the above transaction.
Inputs []PInput
// Outputs contains all information required to spend any outputs
// produced by this PSBT.
Outputs []POutput
// Unknowns are the set of custom types (global only) within this PSBT.
Unknowns []Unknown
} }
// validateUnsignedTx returns true if the transaction is unsigned. // validateUnsignedTx returns true if the transaction is unsigned. Note that
// Note that more basic sanity requirements, // more basic sanity requirements, such as the presence of inputs and outputs,
// such as the presence of inputs and outputs, is implicitly // is implicitly checked in the call to MsgTx.Deserialize().
// checked in the call to MsgTx.Deserialize()
func validateUnsignedTX(tx *wire.MsgTx) bool { func validateUnsignedTX(tx *wire.MsgTx) bool {
for _, tin := range tx.TxIn { for _, tin := range tx.TxIn {
if len(tin.SignatureScript) != 0 || len(tin.Witness) != 0 { if len(tin.SignatureScript) != 0 || len(tin.Witness) != 0 {
return false return false
} }
} }
return true return true
} }
// NewPsbtFromUnsignedTx creates a new Psbt struct, without // NewFromUnsignedTx creates a new Psbt struct, without any signatures (i.e.
// any signatures (i.e. only the global section is non-empty). // only the global section is non-empty) using the passed unsigned transaction.
func NewPsbtFromUnsignedTx(tx *wire.MsgTx) (*Psbt, error) { func NewFromUnsignedTx(tx *wire.MsgTx) (*Packet, error) {
if !validateUnsignedTX(tx) { if !validateUnsignedTX(tx) {
return nil, ErrInvalidRawTxSigned return nil, ErrInvalidRawTxSigned
@ -153,7 +153,7 @@ func NewPsbtFromUnsignedTx(tx *wire.MsgTx) (*Psbt, error) {
outSlice := make([]POutput, len(tx.TxOut)) outSlice := make([]POutput, len(tx.TxOut))
unknownSlice := make([]Unknown, 0) unknownSlice := make([]Unknown, 0)
retPsbt := Psbt{ retPsbt := Packet{
UnsignedTx: tx, UnsignedTx: tx,
Inputs: inSlice, Inputs: inSlice,
Outputs: outSlice, Outputs: outSlice,
@ -163,52 +163,52 @@ func NewPsbtFromUnsignedTx(tx *wire.MsgTx) (*Psbt, error) {
return &retPsbt, nil return &retPsbt, nil
} }
// NewPsbt returns a new instance of a Psbt struct created // NewFromRawBytes returns a new instance of a Packet struct created by reading
// by reading from a byte slice. If the format is invalid, an error // from a byte slice. If the format is invalid, an error is returned. If the
// is returned. If the argument b64 is true, the passed byte slice // argument b64 is true, the passed byte slice is decoded from base64 encoding
// is decoded from base64 encoding before processing. // 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. // NOTE: To create a Packet from one's own data, rather than reading in a
func NewPsbt(psbtBytes []byte, b64 bool) (*Psbt, error) { // serialization from a counterparty, one should use a psbt.New.
var err error func NewFromRawBytes(r io.Reader, b64 bool) (*Packet, error) {
// If the PSBT is encoded in bas64, then we'll create a new wrapper
// reader that'll allow us to incrementally decode the contents of the
// io.Reader.
if b64 { if b64 {
decoded := make([]byte, base64.StdEncoding.DecodedLen(len(psbtBytes))) based64EncodedReader := r
_, err = base64.StdEncoding.Decode(decoded, psbtBytes) r = base64.NewDecoder(base64.StdEncoding, based64EncodedReader)
if err != nil {
return nil, err
}
psbtBytes = decoded
} }
r := bytes.NewReader(psbtBytes)
// The Psbt struct does not store the fixed magic bytes, // The Packet struct does not store the fixed magic bytes, but they
// but they must be present or the serialization must // must be present or the serialization must be explicitly rejected.
// be explicitly rejected.
var magic [5]byte var magic [5]byte
if _, err = io.ReadFull(r, magic[:]); err != nil { if _, err := io.ReadFull(r, magic[:]); err != nil {
return nil, err return nil, err
} }
if magic != psbtMagic { if magic != psbtMagic {
return nil, ErrInvalidMagicBytes return nil, ErrInvalidMagicBytes
} }
// Next we parse the GLOBAL section. // Next we parse the GLOBAL section. There is currently only 1 known
// There is currently only 1 known key type, UnsignedTx. // key type, UnsignedTx. We insist this exists first; unknowns are
// We insist this exists first; unknowns are allowed, but // allowed, but only after.
// only after.
keyint, keydata, err := getKey(r) keyint, keydata, err := getKey(r)
if err != nil { if err != nil {
return nil, err return nil, err
} }
if uint8(keyint) != PsbtGlobalUnsignedTx || keydata != nil { if GlobalType(keyint) != UnsignedTxType || keydata != nil {
return nil, ErrInvalidPsbtFormat return nil, ErrInvalidPsbtFormat
} }
value, err := wire.ReadVarBytes(r, 0, MaxPsbtValueLength,
"PSBT value") // Now that we've verified the global type is present, we'll decode it
// into a proper unsigned transaction, and validate it.
value, err := wire.ReadVarBytes(
r, 0, MaxPsbtValueLength, "PSBT value",
)
if err != nil { if err != nil {
return nil, err return nil, err
} }
// Attempt to deserialize the unsigned transaction.
msgTx := wire.NewMsgTx(2) msgTx := wire.NewMsgTx(2)
err = msgTx.Deserialize(bytes.NewReader(value)) err = msgTx.Deserialize(bytes.NewReader(value))
if err != nil { if err != nil {
@ -218,8 +218,9 @@ func NewPsbt(psbtBytes []byte, b64 bool) (*Psbt, error) {
return nil, ErrInvalidRawTxSigned return nil, ErrInvalidRawTxSigned
} }
// parse any unknowns that may be present, break at separator // Next we parse any unknowns that may be present, making sure that we
unknownSlice := make([]Unknown, 0) // break at the separator.
var unknownSlice []Unknown
for { for {
keyint, keydata, err := getKey(r) keyint, keydata, err := getKey(r)
if err != nil { if err != nil {
@ -228,13 +229,17 @@ func NewPsbt(psbtBytes []byte, b64 bool) (*Psbt, error) {
if keyint == -1 { if keyint == -1 {
break break
} }
value, err := wire.ReadVarBytes(r, 0, MaxPsbtValueLength,
"PSBT value") value, err := wire.ReadVarBytes(
r, 0, MaxPsbtValueLength, "PSBT value",
)
if err != nil { if err != nil {
return nil, err return nil, err
} }
keyintanddata := []byte{byte(keyint)} keyintanddata := []byte{byte(keyint)}
keyintanddata = append(keyintanddata, keydata...) keyintanddata = append(keyintanddata, keydata...)
newUnknown := Unknown{ newUnknown := Unknown{
Key: keyintanddata, Key: keyintanddata,
Value: value, Value: value,
@ -242,40 +247,40 @@ func NewPsbt(psbtBytes []byte, b64 bool) (*Psbt, error) {
unknownSlice = append(unknownSlice, newUnknown) unknownSlice = append(unknownSlice, newUnknown)
} }
// Next we parse the INPUT section // Next we parse the INPUT section.
inSlice := make([]PInput, len(msgTx.TxIn)) inSlice := make([]PInput, len(msgTx.TxIn))
for i := range msgTx.TxIn { for i := range msgTx.TxIn {
input := PInput{} input := PInput{}
err = input.deserialize(r) err = input.deserialize(r)
if err != nil { if err != nil {
return nil, err return nil, err
} }
inSlice[i] = input inSlice[i] = input
} }
//Next we parse the OUTPUT section // Next we parse the OUTPUT section.
outSlice := make([]POutput, len(msgTx.TxOut)) outSlice := make([]POutput, len(msgTx.TxOut))
for i := range msgTx.TxOut { for i := range msgTx.TxOut {
output := POutput{} output := POutput{}
err = output.deserialize(r) err = output.deserialize(r)
if err != nil { if err != nil {
return nil, err return nil, err
} }
outSlice[i] = output outSlice[i] = output
} }
// Populate the new Psbt object // Populate the new Packet object
newPsbt := Psbt{ newPsbt := Packet{
UnsignedTx: msgTx, UnsignedTx: msgTx,
Inputs: inSlice, Inputs: inSlice,
Outputs: outSlice, Outputs: outSlice,
Unknowns: unknownSlice, Unknowns: unknownSlice,
} }
// Extended sanity checking is applied here
// to make sure the externally-passed Psbt follows // Extended sanity checking is applied here to make sure the
// all the rules. // externally-passed Packet follows all the rules.
if err = newPsbt.SanityCheck(); err != nil { if err = newPsbt.SanityCheck(); err != nil {
return nil, err return nil, err
} }
@ -283,66 +288,82 @@ func NewPsbt(psbtBytes []byte, b64 bool) (*Psbt, error) {
return &newPsbt, nil return &newPsbt, nil
} }
// Serialize creates a binary serialization of the referenced // Serialize creates a binary serialization of the referenced Packet struct
// Psbt struct with lexicographical ordering (by key) of the subsections // with lexicographical ordering (by key) of the subsections.
func (p *Psbt) Serialize() ([]byte, error) { func (p *Packet) Serialize(w io.Writer) error {
serPsbt := []byte{} // First we write out the precise set of magic bytes that identify a
serPsbt = append(serPsbt, psbtMagic[:]...) // valid PSBT transaction.
if _, err := w.Write(psbtMagic[:]); err != nil {
return err
}
// Create serialization of unsignedtx // Next we prep to write out the unsigned transaction by first
serializedTx := bytes.NewBuffer(make([]byte, 0, // serializing it into an intermediate buffer.
p.UnsignedTx.SerializeSize())) serializedTx := bytes.NewBuffer(
make([]byte, 0, p.UnsignedTx.SerializeSize()),
)
if err := p.UnsignedTx.Serialize(serializedTx); err != nil { if err := p.UnsignedTx.Serialize(serializedTx); err != nil {
return nil, err return err
} }
var buf bytes.Buffer
err := serializeKVPairWithType(&buf, PsbtGlobalUnsignedTx, // Now that we have the serialized transaction, we'll write it out to
nil, serializedTx.Bytes()) // the proper global type.
err := serializeKVPairWithType(
w, uint8(UnsignedTxType), nil, serializedTx.Bytes(),
)
if err != nil { if err != nil {
return nil, err return err
}
// With that our global section is done, so we'll write out the
// separator.
separator := []byte{0x00}
if _, err := w.Write(separator); err != nil {
return err
} }
serPsbt = append(serPsbt, buf.Bytes()...)
serPsbt = append(serPsbt, 0x00)
for _, pInput := range p.Inputs { for _, pInput := range p.Inputs {
var buf bytes.Buffer err := pInput.serialize(w)
err := pInput.serialize(&buf)
if err != nil { if err != nil {
return nil, err return err
}
if _, err := w.Write(separator); err != nil {
return err
} }
serPsbt = append(serPsbt, buf.Bytes()...)
serPsbt = append(serPsbt, 0x00)
} }
for _, pOutput := range p.Outputs { for _, pOutput := range p.Outputs {
var buf bytes.Buffer err := pOutput.serialize(w)
err := pOutput.serialize(&buf)
if err != nil { if err != nil {
return nil, err return err
}
if _, err := w.Write(separator); err != nil {
return err
} }
serPsbt = append(serPsbt, buf.Bytes()...)
serPsbt = append(serPsbt, 0x00)
} }
return serPsbt, nil return nil
} }
// B64Encode returns the base64 encoding of the serialization of // B64Encode returns the base64 encoding of the serialization of
// the current PSBT, or an error if the encoding fails. // the current PSBT, or an error if the encoding fails.
func (p *Psbt) B64Encode() (string, error) { func (p *Packet) B64Encode() (string, error) {
raw, err := p.Serialize() var b bytes.Buffer
if err != nil { if err := p.Serialize(&b); err != nil {
return "", err return "", err
} }
return base64.StdEncoding.EncodeToString(raw), nil
return base64.StdEncoding.EncodeToString(b.Bytes()), nil
} }
// IsComplete returns true only if all of the inputs are // IsComplete returns true only if all of the inputs are
// finalized; this is particularly important in that it decides // finalized; this is particularly important in that it decides
// whether the final extraction to a network serialized signed // whether the final extraction to a network serialized signed
// transaction will be possible. // transaction will be possible.
func (p *Psbt) IsComplete() bool { func (p *Packet) IsComplete() bool {
for i := 0; i < len(p.UnsignedTx.TxIn); i++ { for i := 0; i < len(p.UnsignedTx.TxIn); i++ {
if !isFinalized(p, i) { if !isFinalized(p, i) {
return false return false
@ -353,7 +374,7 @@ func (p *Psbt) IsComplete() bool {
// SanityCheck checks conditions on a PSBT to ensure that it obeys the // SanityCheck checks conditions on a PSBT to ensure that it obeys the
// rules of BIP174, and returns true if so, false if not. // rules of BIP174, and returns true if so, false if not.
func (p *Psbt) SanityCheck() error { func (p *Packet) SanityCheck() error {
if !validateUnsignedTX(p.UnsignedTx) { if !validateUnsignedTX(p.UnsignedTx) {
return ErrInvalidRawTxSigned return ErrInvalidRawTxSigned