github.com/bytom/bytom@v1.1.2-0.20221014091027-bbcba3df6075/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 // Outputs return outputs of transactions 49 func (b *TemplateBuilder) Outputs() []*types.TxOutput { 50 return b.outputs 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 tpl.Transaction = types.NewTx(*tx) 140 tpl.Fee = tx.Fee() 141 return tpl, tx, nil 142 }