OSDN Git Service

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