OSDN Git Service

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