forked from echovl/cardano-go
-
Notifications
You must be signed in to change notification settings - Fork 2
/
tx_builder.go
122 lines (102 loc) · 3.22 KB
/
tx_builder.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
package cardano
import (
"encoding/hex"
"github.com/tclairet/cardano-go/crypto"
"golang.org/x/crypto/blake2b"
)
const maxUint64 uint64 = 1<<64 - 1
type TXBuilderInput struct {
input TransactionInput
amount uint64
}
type TXBuilderOutput struct {
address Address
amount uint64
}
type TXBuilder struct {
tx Transaction
protocol ProtocolParams
inputs []TXBuilderInput
outputs []TransactionOutput
ttl uint64
fee uint64
vkeys map[string]crypto.ExtendedVerificationKey
pkeys map[string]crypto.ExtendedSigningKey
}
func NewTxBuilder(protocol ProtocolParams) *TXBuilder {
return &TXBuilder{
protocol: protocol,
vkeys: map[string]crypto.ExtendedVerificationKey{},
pkeys: map[string]crypto.ExtendedSigningKey{},
}
}
func (builder *TXBuilder) AddInput(xvk crypto.ExtendedVerificationKey, txId TransactionID, index, amount uint64) {
input := TXBuilderInput{input: TransactionInput{ID: txId.Bytes(), Index: index}, amount: amount}
builder.inputs = append(builder.inputs, input)
vkeyHashBytes := blake2b.Sum256(xvk)
vkeyHashString := hex.EncodeToString(vkeyHashBytes[:])
builder.vkeys[vkeyHashString] = xvk
}
func (builder *TXBuilder) AddInputWithoutSig(txId TransactionID, index, amount uint64) {
input := TXBuilderInput{input: TransactionInput{ID: txId.Bytes(), Index: index}, amount: amount}
builder.inputs = append(builder.inputs, input)
}
func (builder *TXBuilder) AddOutput(address Address, amount uint64) {
output := TransactionOutput{Address: address.Bytes(), Amount: amount}
builder.outputs = append(builder.outputs, output)
}
func (builder *TXBuilder) SetTtl(ttl uint64) {
builder.ttl = ttl
}
func (builder *TXBuilder) SetFee(fee uint64) {
builder.fee = fee
}
// This assumes that the builder inputs and outputs are defined
func (builder *TXBuilder) AddFee(address Address) error {
inputAmount := uint64(0)
for _, txIn := range builder.inputs {
inputAmount += txIn.amount
}
body := builder.buildBody()
if err := body.addFee(inputAmount, address, builder.protocol); err != nil {
return err
}
builder.outputs = body.Outputs
builder.fee = body.Fee
return nil
}
func (builder *TXBuilder) Sign(xsk crypto.ExtendedSigningKey) {
pkeyHashBytes := blake2b.Sum256(xsk)
pkeyHashString := hex.EncodeToString(pkeyHashBytes[:])
builder.pkeys[pkeyHashString] = xsk
}
func (builder *TXBuilder) Build() Transaction {
if len(builder.pkeys) != len(builder.vkeys) {
panic("missing signatures")
}
body := builder.buildBody()
witnessSet := TransactionWitnessSet{}
txHash := blake2b.Sum256(body.Bytes())
for _, pkey := range builder.pkeys {
publicKey := pkey.ExtendedVerificationKey()[:32]
signature := pkey.Sign(txHash[:])
witness := VKeyWitness{VKey: publicKey, Signature: signature}
witnessSet.VKeyWitnessSet = append(witnessSet.VKeyWitnessSet, witness)
}
return Transaction{Body: body, WitnessSet: witnessSet, Metadata: nil}
}
func (builder *TXBuilder) buildBody() TransactionBody {
inputs := make([]TransactionInput, len(builder.inputs))
for i, txInput := range builder.inputs {
inputs[i] = TransactionInput{
ID: txInput.input.ID,
Index: txInput.input.Index,
}
}
return TransactionBody{
Inputs: inputs,
Outputs: builder.outputs,
Fee: builder.fee,
Ttl: builder.ttl,
}
}