-
Notifications
You must be signed in to change notification settings - Fork 12
/
extractor.go
142 lines (122 loc) · 3.45 KB
/
extractor.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
package psetv2
import (
"bytes"
"fmt"
"github.com/btcsuite/btcd/txscript"
"github.com/btcsuite/btcd/wire"
"github.com/vulpemventures/go-elements/elementsutil"
"github.com/vulpemventures/go-elements/transaction"
)
var (
ErrExtractorForbiddenExtraction = fmt.Errorf(
"pset must be complete to extract final transaction",
)
)
func Extract(p *Pset) (*transaction.Transaction, error) {
if err := p.SanityCheck(); err != nil {
return nil, fmt.Errorf("invalid pset: %s", err)
}
if !p.IsComplete() {
return nil, ErrExtractorForbiddenExtraction
}
tx := transaction.NewTx(int32(p.Global.TxVersion))
tx.Locktime = p.Locktime()
for _, in := range p.Inputs {
txIn := &transaction.TxInput{
Hash: in.PreviousTxid,
Index: in.PreviousTxIndex,
Sequence: in.Sequence,
}
var issuance *transaction.TxIssuance
if in.IssuanceValue > 0 || in.IssuanceValueCommitment != nil {
value := in.IssuanceValueCommitment
if value == nil {
value, _ = elementsutil.ValueToBytes(in.IssuanceValue)
}
tokenValue := in.IssuanceInflationKeysCommitment
if tokenValue == nil {
tokenValue = []byte{0x00}
if in.IssuanceInflationKeys > 0 {
tokenValue, _ = elementsutil.ValueToBytes(in.IssuanceInflationKeys)
}
}
issuance = &transaction.TxIssuance{
AssetBlindingNonce: in.IssuanceBlindingNonce,
AssetEntropy: in.IssuanceAssetEntropy,
AssetAmount: value,
TokenAmount: tokenValue,
}
}
txIn.Issuance = issuance
if in.IssuanceValueRangeproof != nil {
txIn.IssuanceRangeProof = in.IssuanceValueRangeproof
}
if in.IssuanceInflationKeysRangeproof != nil {
txIn.InflationRangeProof = in.IssuanceInflationKeysRangeproof
}
txIn.IsPegin = in.PeginWitness != nil
if txIn.IsPegin {
txIn.PeginWitness = in.PeginWitness
}
if in.FinalScriptSig != nil {
txIn.Script = in.FinalScriptSig
}
if in.FinalScriptWitness != nil {
// In order to set the witness, need to re-deserialize
// the field as encoded within the PSET packet. For
// each input, the witness is encoded as a stack with
// one or more items.
witnessReader := bytes.NewReader(
in.FinalScriptWitness,
)
// First we extract the number of witness elements
// encoded in the above witnessReader.
witCount, err := wire.ReadVarInt(witnessReader, 0)
if err != nil {
return nil, err
}
// Now that we know how may inputs we'll need, we'll
// construct a packing slice, then read out each input
// (with a varint prefix) from the witnessReader.
txIn.Witness = make(transaction.TxWitness, witCount)
for j := uint64(0); j < witCount; j++ {
wit, err := wire.ReadVarBytes(
witnessReader, 0, txscript.MaxScriptSize, "witness",
)
if err != nil {
return nil, err
}
txIn.Witness[j] = wit
}
}
tx.AddInput(txIn)
}
for _, out := range p.Outputs {
txOut := &transaction.TxOutput{
Script: out.Script,
}
value := out.ValueCommitment
if value == nil {
value, _ = elementsutil.ValueToBytes(out.Value)
}
txOut.Value = value
asset := out.AssetCommitment
if asset == nil {
asset = append([]byte{0x01}, out.Asset...)
}
txOut.Asset = asset
nonce := []byte{0x00}
if out.EcdhPubkey != nil {
nonce = out.EcdhPubkey
}
txOut.Nonce = nonce
if out.ValueRangeproof != nil {
txOut.RangeProof = out.ValueRangeproof
}
if out.AssetSurjectionProof != nil {
txOut.SurjectionProof = out.AssetSurjectionProof
}
tx.AddOutput(txOut)
}
return tx, nil
}