github.com/Bytom/bytom@v1.1.2-0.20210127130405-ae40204c0b09/blockchain/txbuilder/builder.go (about) 1 package txbuilder 2 3 import ( 4 "math" 5 "time" 6 7 "github.com/bytom/bytom/errors" 8 "github.com/bytom/bytom/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 }