-
Notifications
You must be signed in to change notification settings - Fork 2
/
builder.go
137 lines (117 loc) · 3.68 KB
/
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
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
package txbuilder
import (
"math"
"time"
"github.com/bytom/bytom-classic/errors"
"github.com/bytom/bytom-classic/protocol/bc/types"
)
// NewBuilder return new TemplateBuilder instance
func NewBuilder(maxTime time.Time) *TemplateBuilder {
return &TemplateBuilder{maxTime: maxTime}
}
// TemplateBuilder is struct of building transactions
type TemplateBuilder struct {
base *types.TxData
inputs []*types.TxInput
outputs []*types.TxOutput
signingInstructions []*SigningInstruction
minTime time.Time
maxTime time.Time
timeRange uint64
rollbacks []func()
callbacks []func() error
}
// AddInput add inputs of transactions
func (b *TemplateBuilder) AddInput(in *types.TxInput, sigInstruction *SigningInstruction) error {
if in.InputType() != types.CoinbaseInputType && in.Amount() > math.MaxInt64 {
return errors.WithDetailf(ErrBadAmount, "amount %d exceeds maximum value 2^63", in.Amount())
}
b.inputs = append(b.inputs, in)
b.signingInstructions = append(b.signingInstructions, sigInstruction)
return nil
}
// AddOutput add outputs of transactions
func (b *TemplateBuilder) AddOutput(o *types.TxOutput) error {
if o.Amount > math.MaxInt64 {
return errors.WithDetailf(ErrBadAmount, "amount %d exceeds maximum value 2^63", o.Amount)
}
b.outputs = append(b.outputs, o)
return nil
}
// InputCount return number of input in the template builder
func (b *TemplateBuilder) InputCount() int {
return len(b.inputs)
}
// RestrictMinTime set minTime
func (b *TemplateBuilder) RestrictMinTime(t time.Time) {
if t.After(b.minTime) {
b.minTime = t
}
}
// RestrictMaxTime set maxTime
func (b *TemplateBuilder) RestrictMaxTime(t time.Time) {
if t.Before(b.maxTime) {
b.maxTime = t
}
}
// MaxTime return maxTime
func (b *TemplateBuilder) MaxTime() time.Time {
return b.maxTime
}
// OnRollback registers a function that can be
// used to attempt to undo any side effects of building
// actions. For example, it might cancel any reservations
// reservations that were made on UTXOs in a spend action.
// Rollback is a "best-effort" operation and not guaranteed
// to succeed. Each action's side effects, if any, must be
// designed with this in mind.
func (b *TemplateBuilder) OnRollback(rollbackFn func()) {
b.rollbacks = append(b.rollbacks, rollbackFn)
}
// OnBuild registers a function that will be run after all
// actions have been successfully built.
func (b *TemplateBuilder) OnBuild(buildFn func() error) {
b.callbacks = append(b.callbacks, buildFn)
}
// Rollback action for handle fail build
func (b *TemplateBuilder) Rollback() {
for _, f := range b.rollbacks {
f()
}
}
// Build build transactions with template
func (b *TemplateBuilder) Build() (*Template, *types.TxData, error) {
// Run any building callbacks.
for _, cb := range b.callbacks {
err := cb()
if err != nil {
return nil, nil, err
}
}
tpl := &Template{}
tx := b.base
if tx == nil {
tx = &types.TxData{
Version: 1,
}
}
if b.timeRange != 0 {
tx.TimeRange = b.timeRange
}
// Add all the built outputs.
tx.Outputs = append(tx.Outputs, b.outputs...)
// Add all the built inputs and their corresponding signing instructions.
for i, in := range b.inputs {
instruction := b.signingInstructions[i]
instruction.Position = uint32(len(tx.Inputs))
// Empty signature arrays should be serialized as empty arrays, not null.
if instruction.WitnessComponents == nil {
instruction.WitnessComponents = []witnessComponent{}
}
tpl.SigningInstructions = append(tpl.SigningInstructions, instruction)
tx.Inputs = append(tx.Inputs, in)
}
tpl.Transaction = types.NewTx(*tx)
tpl.Fee = CalculateTxFee(tpl.Transaction)
return tpl, tx, nil
}