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  }