OSDN Git Service

b93b6dbed5475e8d83d2ca00dda6bab9a945a1b2
[bytom/vapor.git] / blockchain / txbuilder / builder.go
1 package txbuilder
2
3 import (
4         "math"
5         "time"
6
7         "github.com/vapor/errors"
8         "github.com/vapor/protocol/bc/types"
9 )
10
11 // NewBuilder return new TemplateBuilder instance
12 func NewBuilder(maxTime time.Time) *TemplateBuilder {
13         return &TemplateBuilder{maxTime: maxTime}
14 }
15
16 // TemplateBuilder is struct of building transactions
17 type TemplateBuilder struct {
18         base                *types.TxData
19         inputs              []*types.TxInput
20         outputs             []*types.TxOutput
21         signingInstructions []*SigningInstruction
22         minTime             time.Time
23         maxTime             time.Time
24         timeRange           uint64
25         rollbacks           []func()
26         callbacks           []func() error
27 }
28
29 // AddInput add inputs of transactions
30 func (b *TemplateBuilder) AddInput(in *types.TxInput, sigInstruction *SigningInstruction) error {
31         if in.InputType() != types.CoinbaseInputType && in.Amount() > math.MaxInt64 {
32                 return errors.WithDetailf(ErrBadAmount, "amount %d exceeds maximum value 2^63", in.Amount())
33         }
34         b.inputs = append(b.inputs, in)
35         b.signingInstructions = append(b.signingInstructions, sigInstruction)
36         return nil
37 }
38
39 // AddOutput add outputs of transactions
40 func (b *TemplateBuilder) AddOutput(o *types.TxOutput) error {
41         if o.Amount > math.MaxInt64 {
42                 return errors.WithDetailf(ErrBadAmount, "amount %d exceeds maximum value 2^63", o.Amount)
43         }
44         b.outputs = append(b.outputs, o)
45         return nil
46 }
47
48 // InputCount return number of input in the template builder
49 func (b *TemplateBuilder) InputCount() int {
50         return len(b.inputs)
51 }
52
53 // RestrictMinTime set minTime
54 func (b *TemplateBuilder) RestrictMinTime(t time.Time) {
55         if t.After(b.minTime) {
56                 b.minTime = t
57         }
58 }
59
60 // RestrictMaxTime set maxTime
61 func (b *TemplateBuilder) RestrictMaxTime(t time.Time) {
62         if t.Before(b.maxTime) {
63                 b.maxTime = t
64         }
65 }
66
67 // MaxTime return maxTime
68 func (b *TemplateBuilder) MaxTime() time.Time {
69         return b.maxTime
70 }
71
72 // OnRollback registers a function that can be
73 // used to attempt to undo any side effects of building
74 // actions. For example, it might cancel any reservations
75 // reservations that were made on UTXOs in a spend action.
76 // Rollback is a "best-effort" operation and not guaranteed
77 // to succeed. Each action's side effects, if any, must be
78 // designed with this in mind.
79 func (b *TemplateBuilder) OnRollback(rollbackFn func()) {
80         b.rollbacks = append(b.rollbacks, rollbackFn)
81 }
82
83 // OnBuild registers a function that will be run after all
84 // actions have been successfully built.
85 func (b *TemplateBuilder) OnBuild(buildFn func() error) {
86         b.callbacks = append(b.callbacks, buildFn)
87 }
88
89 // Rollback action for handle fail build
90 func (b *TemplateBuilder) Rollback() {
91         for _, f := range b.rollbacks {
92                 f()
93         }
94 }
95
96 // Build build transactions with template
97 func (b *TemplateBuilder) Build() (*Template, *types.TxData, error) {
98         // Run any building callbacks.
99         for _, cb := range b.callbacks {
100                 err := cb()
101                 if err != nil {
102                         return nil, nil, err
103                 }
104         }
105
106         tpl := &Template{}
107         tx := b.base
108         if tx == nil {
109                 tx = &types.TxData{
110                         Version: 1,
111                 }
112         }
113
114         if b.timeRange != 0 {
115                 tx.TimeRange = b.timeRange
116         }
117
118         // Add all the built outputs.
119         tx.Outputs = append(tx.Outputs, b.outputs...)
120
121         // Add all the built inputs and their corresponding signing instructions.
122         for i, in := range b.inputs {
123                 instruction := b.signingInstructions[i]
124                 instruction.Position = uint32(len(tx.Inputs))
125
126                 // Empty signature arrays should be serialized as empty arrays, not null.
127                 if instruction.WitnessComponents == nil {
128                         instruction.WitnessComponents = []witnessComponent{}
129                 }
130                 tpl.SigningInstructions = append(tpl.SigningInstructions, instruction)
131                 tx.Inputs = append(tx.Inputs, in)
132         }
133
134         tpl.Transaction = types.NewTx(*tx)
135         tpl.Fee = CalculateTxFee(tpl.Transaction)
136         return tpl, tx, nil
137 }