psbt: rename psbt.Psbt to psbt.Packet, rename existing constructors
This commit is contained in:
parent
014f58c55d
commit
3385fba2f2
1 changed files with 119 additions and 98 deletions
215
psbt/psbt.go
215
psbt/psbt.go
|
@ -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 contains all the information needed to properly sign this
|
||||||
|
// target input within the above transaction.
|
||||||
Inputs []PInput
|
Inputs []PInput
|
||||||
|
|
||||||
|
// Outputs contains all information required to spend any outputs
|
||||||
|
// produced by this PSBT.
|
||||||
Outputs []POutput
|
Outputs []POutput
|
||||||
Unknowns []Unknown // Data of unknown type at global scope
|
|
||||||
|
// 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
|
|
||||||
}
|
// The Packet struct does not store the fixed magic bytes, but they
|
||||||
r := bytes.NewReader(psbtBytes)
|
// must be present or the serialization must be explicitly rejected.
|
||||||
// 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
|
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
|
||||||
}
|
|
||||||
serPsbt = append(serPsbt, buf.Bytes()...)
|
|
||||||
serPsbt = append(serPsbt, 0x00)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return serPsbt, nil
|
if _, err := w.Write(separator); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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
|
||||||
|
|
Loading…
Reference in a new issue