7 "github.com/vapor/blockchain/txbuilder"
8 bytomtypes "github.com/vapor/claim/bytom/protocolbc/types"
9 "github.com/vapor/consensus"
10 "github.com/vapor/errors"
13 // NewBuilder return new TemplateBuilder instance
14 func NewBuilder(maxTime time.Time) *TemplateBuilder {
15 return &TemplateBuilder{maxTime: maxTime}
18 // TemplateBuilder is struct of building transactions
19 type TemplateBuilder struct {
20 base *bytomtypes.TxData
21 inputs []*bytomtypes.TxInput
22 outputs []*bytomtypes.TxOutput
23 signingInstructions []*SigningInstruction
29 callbacks []func() error
32 // AddInput add inputs of transactions
33 func (b *TemplateBuilder) AddInput(in *bytomtypes.TxInput, sigInstruction *SigningInstruction) error {
34 if in.InputType() != bytomtypes.CoinbaseInputType && in.Amount() > math.MaxInt64 {
35 return errors.WithDetailf(txbuilder.ErrBadAmount, "amount %d exceeds maximum value 2^63", in.Amount())
37 b.inputs = append(b.inputs, in)
38 b.signingInstructions = append(b.signingInstructions, sigInstruction)
42 // AddOutput add outputs of transactions
43 func (b *TemplateBuilder) AddOutput(o *bytomtypes.TxOutput) error {
44 if o.Amount > math.MaxInt64 {
45 return errors.WithDetailf(txbuilder.ErrBadAmount, "amount %d exceeds maximum value 2^63", o.Amount)
47 b.outputs = append(b.outputs, o)
51 // RestrictMinTime set minTime
52 func (b *TemplateBuilder) RestrictMinTime(t time.Time) {
53 if t.After(b.minTime) {
58 // RestrictMaxTime set maxTime
59 func (b *TemplateBuilder) RestrictMaxTime(t time.Time) {
60 if t.Before(b.maxTime) {
65 // MaxTime return maxTime
66 func (b *TemplateBuilder) MaxTime() time.Time {
70 // OnRollback registers a function that can be
71 // used to attempt to undo any side effects of building
72 // actions. For example, it might cancel any reservations
73 // reservations that were made on UTXOs in a spend action.
74 // Rollback is a "best-effort" operation and not guaranteed
75 // to succeed. Each action's side effects, if any, must be
76 // designed with this in mind.
77 func (b *TemplateBuilder) OnRollback(rollbackFn func()) {
78 b.rollbacks = append(b.rollbacks, rollbackFn)
81 // OnBuild registers a function that will be run after all
82 // actions have been successfully built.
83 func (b *TemplateBuilder) OnBuild(buildFn func() error) {
84 b.callbacks = append(b.callbacks, buildFn)
87 func (b *TemplateBuilder) rollback() {
88 for _, f := range b.rollbacks {
93 // Build build transactions with template
94 func (b *TemplateBuilder) Build() (*Template, *bytomtypes.TxData, error) {
95 // Run any building callbacks.
96 for _, cb := range b.callbacks {
106 tx = &bytomtypes.TxData{
111 if b.timeRange != 0 {
112 tx.TimeRange = b.timeRange
115 // Add all the built outputs.
116 tx.Outputs = append(tx.Outputs, b.outputs...)
118 // Add all the built inputs and their corresponding signing instructions.
119 for i, in := range b.inputs {
120 instruction := b.signingInstructions[i]
121 instruction.Position = uint32(len(tx.Inputs))
123 // Empty signature arrays should be serialized as empty arrays, not null.
124 if instruction.WitnessComponents == nil {
125 instruction.WitnessComponents = []witnessComponent{}
127 tpl.SigningInstructions = append(tpl.SigningInstructions, instruction)
128 tx.Inputs = append(tx.Inputs, in)
131 tpl.Transaction = bytomtypes.NewTx(*tx)
132 tpl.Fee = CalculateTxFee(tpl.Transaction)
136 // CalculateTxFee calculate transaction fee
137 func CalculateTxFee(tx *bytomtypes.Tx) (fee uint64) {
138 totalInputBTM := uint64(0)
139 totalOutputBTM := uint64(0)
141 for _, input := range tx.Inputs {
142 if input.InputType() != bytomtypes.CoinbaseInputType && input.AssetID() == *consensus.BTMAssetID {
143 totalInputBTM += input.Amount()
147 for _, output := range tx.Outputs {
148 if *output.AssetId == *consensus.BTMAssetID {
149 totalOutputBTM += output.Amount
153 fee = totalInputBTM - totalOutputBTM