8 "github.com/bytom/errors"
9 "github.com/bytom/protocol/bc/legacy"
12 func NewBuilder(maxTime time.Time) *TemplateBuilder {
13 return &TemplateBuilder{maxTime: maxTime}
16 type TemplateBuilder struct {
18 inputs []*legacy.TxInput
19 outputs []*legacy.TxOutput
20 signingInstructions []*SigningInstruction
25 callbacks []func() error
28 func (b *TemplateBuilder) AddInput(in *legacy.TxInput, sigInstruction *SigningInstruction) error {
29 if !in.IsCoinbase() && in.Amount() > math.MaxInt64 {
30 return errors.WithDetailf(ErrBadAmount, "amount %d exceeds maximum value 2^63", in.Amount())
32 b.inputs = append(b.inputs, in)
33 b.signingInstructions = append(b.signingInstructions, sigInstruction)
37 func (b *TemplateBuilder) AddOutput(o *legacy.TxOutput) error {
38 if o.Amount > math.MaxInt64 {
39 return errors.WithDetailf(ErrBadAmount, "amount %d exceeds maximum value 2^63", o.Amount)
41 b.outputs = append(b.outputs, o)
45 func (b *TemplateBuilder) RestrictMinTime(t time.Time) {
46 if t.After(b.minTime) {
51 func (b *TemplateBuilder) RestrictMaxTime(t time.Time) {
52 if t.Before(b.maxTime) {
57 func (b *TemplateBuilder) MaxTime() time.Time {
61 // OnRollback registers a function that can be
62 // used to attempt to undo any side effects of building
63 // actions. For example, it might cancel any reservations
64 // reservations that were made on UTXOs in a spend action.
65 // Rollback is a "best-effort" operation and not guaranteed
66 // to succeed. Each action's side effects, if any, must be
67 // designed with this in mind.
68 func (b *TemplateBuilder) OnRollback(rollbackFn func()) {
69 b.rollbacks = append(b.rollbacks, rollbackFn)
72 // OnBuild registers a function that will be run after all
73 // actions have been successfully built.
74 func (b *TemplateBuilder) OnBuild(buildFn func() error) {
75 b.callbacks = append(b.callbacks, buildFn)
78 func (b *TemplateBuilder) setReferenceData(data []byte) error {
79 if b.base != nil && len(b.base.ReferenceData) != 0 && !bytes.Equal(b.base.ReferenceData, data) {
80 return errors.Wrap(ErrBadRefData)
82 if len(b.referenceData) != 0 && !bytes.Equal(b.referenceData, data) {
83 return errors.Wrap(ErrBadRefData)
85 b.referenceData = data
89 func (b *TemplateBuilder) rollback() {
90 for _, f := range b.rollbacks {
95 func (b *TemplateBuilder) Build() (*Template, *legacy.TxData, error) {
96 // Run any building callbacks.
97 for _, cb := range b.callbacks {
113 // Set transaction reference data if applicable.
114 if len(b.referenceData) > 0 {
115 tx.ReferenceData = b.referenceData
118 // Add all the built outputs.
119 tx.Outputs = append(tx.Outputs, b.outputs...)
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))
126 // Empty signature arrays should be serialized as empty arrays, not null.
127 if instruction.WitnessComponents == nil {
128 instruction.WitnessComponents = []witnessComponent{}
130 tpl.SigningInstructions = append(tpl.SigningInstructions, instruction)
131 tx.Inputs = append(tx.Inputs, in)
133 tpl.Transaction = legacy.NewTx(*tx)