-
Notifications
You must be signed in to change notification settings - Fork 47
/
fee_decorator.go
86 lines (77 loc) · 2.37 KB
/
fee_decorator.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
package msgfee
import (
"github.com/iov-one/weave"
"github.com/iov-one/weave/coin"
"github.com/iov-one/weave/errors"
"github.com/iov-one/weave/orm"
)
// FeeDecorator implements a decorator that for each processed transaction
// attach an additional fee to the result. Each fee is declared per
// transaction type. If fee is not set (zero value) then this decorator does
// not increase the required fee value.
// Additional fee is attached to only those transaction results that represent
// a success.
type FeeDecorator struct {
bucket orm.ModelBucket
}
var _ weave.Decorator = (*FeeDecorator)(nil)
// NewFeeDecorator returns a decorator that is upading the cost of processing
// each message according to the fee configured per each message type.
func NewFeeDecorator() *FeeDecorator {
return &FeeDecorator{
bucket: NewMsgFeeBucket(),
}
}
func (d *FeeDecorator) Check(ctx weave.Context, store weave.KVStore, tx weave.Tx, next weave.Checker) (*weave.CheckResult, error) {
res, err := next.Check(ctx, store, tx)
if err != nil {
return nil, err
}
fee, err := txFee(d.bucket, store, tx)
if err != nil {
return nil, err
}
if !coin.IsEmpty(fee) {
total, err := res.RequiredFee.Add(*fee)
if err != nil {
return nil, errors.Wrap(err, "cannot apply message type fee")
}
res.RequiredFee = total
}
return res, nil
}
func (d *FeeDecorator) Deliver(ctx weave.Context, store weave.KVStore, tx weave.Tx, next weave.Deliverer) (*weave.DeliverResult, error) {
res, err := next.Deliver(ctx, store, tx)
if err != nil {
return nil, err
}
fee, err := txFee(d.bucket, store, tx)
if err != nil {
return nil, err
}
if !coin.IsEmpty(fee) {
total, err := res.RequiredFee.Add(*fee)
if err != nil {
return nil, errors.Wrapf(err, "cannot apply message type fee to %v", res.RequiredFee)
}
res.RequiredFee = total
}
return res, nil
}
// txFee returns the fee value for a given transaction as configured in the
// store. This function returns nil fee value if none was set.
func txFee(fees orm.ModelBucket, store weave.KVStore, tx weave.Tx) (*coin.Coin, error) {
msg, err := tx.GetMsg()
if err != nil {
return nil, errors.Wrap(err, "cannot get message")
}
var fee MsgFee
switch err := fees.One(store, []byte(msg.Path()), &fee); {
case err == nil:
return &fee.Fee, nil
case errors.ErrNotFound.Is(err):
return nil, nil
default:
return nil, errors.Wrap(err, "cannot get fee")
}
}