Skip to content

Commit 92d4251

Browse files
authored
592 fee model (#595)
* #592 add fee model to action type * #592 add fee model to action type * #592 ignore package-interface naming lint rule * #592 update pb file of transaction : add model + service for getTxMinimumFee api * #592 add handler for calculate minimum fee api * #592 fix GetTransactionMinimumFee request * #592 fix wrong type * #592 add api client for testing get minimum fee
1 parent dd11961 commit 92d4251

23 files changed

+594
-120
lines changed

.golangci.yml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -143,6 +143,8 @@ issues:
143143
text: "copylocks: literal copies lock value"
144144
linters:
145145
- govet
146+
- path: "(.+).go"
147+
text: "type name will be used as"
146148
- path: "(.+)_test.go"
147149
text: "copylocks: range var tt copies lock:"
148150
linters:
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
package main
2+
3+
import (
4+
"context"
5+
"fmt"
6+
7+
"github.com/sirupsen/logrus"
8+
log "github.com/sirupsen/logrus"
9+
"github.com/spf13/viper"
10+
rpc_model "github.com/zoobc/zoobc-core/common/model"
11+
rpc_service "github.com/zoobc/zoobc-core/common/service"
12+
"github.com/zoobc/zoobc-core/common/util"
13+
"google.golang.org/grpc"
14+
)
15+
16+
func main() {
17+
var apiRPCPort int
18+
if err := util.LoadConfig("../../../resource", "config", "toml"); err != nil {
19+
logrus.Fatal(err)
20+
} else {
21+
apiRPCPort = viper.GetInt("apiRPCPort")
22+
if apiRPCPort == 0 {
23+
apiRPCPort = 8080
24+
}
25+
}
26+
27+
conn, err := grpc.Dial(fmt.Sprintf(":%d", apiRPCPort), grpc.WithInsecure())
28+
if err != nil {
29+
log.Fatalf("did not connect: %s", err)
30+
}
31+
defer conn.Close()
32+
33+
c := rpc_service.NewTransactionServiceClient(conn)
34+
35+
request := &rpc_model.GetTransactionMinimumFeeRequest{
36+
TransactionBytes: []byte{
37+
1, 0, 0, 0, 1, 191, 62, 75, 94, 0, 0, 0, 0, 44, 0, 0, 0, 122, 85, 107, 50, 109, 99, 103, 57, 118,
38+
110, 81, 115, 102, 79, 111, 110, 49, 84, 45, 51, 102, 108, 55, 56, 80, 78, 106, 100, 109, 68, 55,
39+
49, 66, 54, 86, 99, 45, 101, 72, 65, 56, 102, 79, 54, 44, 0, 0, 0, 79, 110, 69, 89, 122, 73, 45,
40+
69, 77, 86, 54, 85, 84, 102, 111, 85, 69, 122, 112, 81, 85, 106, 107, 83, 108, 110, 113, 66, 56,
41+
50, 45, 83, 121, 82, 78, 55, 52, 54, 57, 108, 74, 84, 87, 72, 1, 0, 0, 0, 0, 0, 0, 0, 8, 0, 0, 0,
42+
100, 0, 0, 0, 0, 0, 0, 0, 44, 0, 0, 0, 79, 110, 69, 89, 122, 73, 45, 69, 77, 86, 54, 85, 84, 102,
43+
111, 85, 69, 122, 112, 81, 85, 106, 107, 83, 108, 110, 113, 66, 56, 50, 45, 83, 121, 82, 78, 55,
44+
52, 54, 57, 108, 74, 84, 87, 72, 1, 0, 0, 0, 0, 0, 0, 0, 141, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
45+
0, 0, 0, 151, 14, 69, 104, 198, 182, 113, 50, 53, 190, 105, 20, 164, 57, 16, 94, 89, 251, 35, 230,
46+
145, 198, 189, 167, 222, 214, 208, 120, 229, 172, 155, 54, 85, 245, 19, 125, 3, 4, 11, 44, 65, 254,
47+
148, 174, 117, 98, 16, 161, 149, 16, 4, 0, 153, 107, 84, 187, 8, 225, 103, 208, 126, 101, 17, 0,
48+
},
49+
}
50+
response, err := c.GetTransactionMinimumFee(context.Background(), request)
51+
52+
if err != nil {
53+
log.Fatalf("error calling rpc_service.GetTransactionMinimumFee: %s", err)
54+
}
55+
56+
log.Printf("response from remote rpc_service.GetTransactionMinimumFee(%v): %v", request, response.GetFee())
57+
58+
}

api/handler/transactionHandler.go

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,3 +64,20 @@ func (th *TransactionHandler) PostTransaction(
6464
Transaction: transaction,
6565
}, nil
6666
}
67+
68+
// GetTransactionMinimumFee handles request to get transaction's minimum fee
69+
func (th *TransactionHandler) GetTransactionMinimumFee(
70+
ctx context.Context,
71+
req *model.GetTransactionMinimumFeeRequest,
72+
) (*model.GetTransactionMinimumFeeResponse, error) {
73+
var (
74+
transactionFee *model.GetTransactionMinimumFeeResponse
75+
err error
76+
)
77+
transactionFee, err = th.Service.GetTransactionMinimumFee(req)
78+
if err != nil {
79+
return nil, err
80+
}
81+
82+
return transactionFee, nil
83+
}

api/service/transactionApiService.go

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,9 @@ type (
2323
GetTransaction(chaintype.ChainType, *model.GetTransactionRequest) (*model.Transaction, error)
2424
GetTransactions(chaintype.ChainType, *model.GetTransactionsRequest) (*model.GetTransactionsResponse, error)
2525
PostTransaction(chaintype.ChainType, *model.PostTransactionRequest) (*model.Transaction, error)
26+
GetTransactionMinimumFee(request *model.GetTransactionMinimumFeeRequest) (
27+
*model.GetTransactionMinimumFeeResponse, error,
28+
)
2629
}
2730

2831
// TransactionService represents struct of TransactionService
@@ -283,3 +286,28 @@ func (ts *TransactionService) PostTransaction(
283286
// return parsed transaction
284287
return tx, nil
285288
}
289+
290+
func (ts *TransactionService) GetTransactionMinimumFee(req *model.GetTransactionMinimumFeeRequest) (
291+
*model.GetTransactionMinimumFeeResponse, error,
292+
) {
293+
var (
294+
txBytes = req.TransactionBytes
295+
err error
296+
)
297+
tx, err := ts.TransactionUtil.ParseTransactionBytes(txBytes, true)
298+
if err != nil {
299+
return nil, status.Error(codes.Internal, err.Error())
300+
}
301+
// get the TypeAction object
302+
txType, err := ts.ActionTypeSwitcher.GetTransactionType(tx)
303+
if err != nil {
304+
return nil, status.Error(codes.Internal, err.Error())
305+
}
306+
minFee, err := txType.GetMinimumFee()
307+
if err != nil {
308+
return nil, err
309+
}
310+
return &model.GetTransactionMinimumFeeResponse{
311+
Fee: minFee,
312+
}, nil
313+
}

common/fee/blockLifeTimeFeeModel.go

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
package fee
2+
3+
import (
4+
"math"
5+
6+
"github.com/zoobc/zoobc-core/common/model"
7+
)
8+
9+
type (
10+
// BlockLifeTimeFeeModel will calculate the transaction fee based on expected lifetime on the chain. `timeout` field
11+
// must be present in the transaction body
12+
BlockLifeTimeFeeModel struct {
13+
blockPeriod int64
14+
feePerBlockPeriod int64
15+
}
16+
)
17+
18+
func NewBlockLifeTimeFeeModel(
19+
blockPeriod, feePerBlockPeriod int64,
20+
) *BlockLifeTimeFeeModel {
21+
return &BlockLifeTimeFeeModel{
22+
blockPeriod: blockPeriod,
23+
feePerBlockPeriod: feePerBlockPeriod,
24+
}
25+
}
26+
27+
func (blt *BlockLifeTimeFeeModel) CalculateTxMinimumFee(
28+
txBody model.TransactionBodyInterface, escrow *model.Escrow,
29+
) (int64, error) {
30+
// timeout / blockPeriod result is ceil
31+
fee := int64(math.Ceil(float64(escrow.Timeout)/float64(blt.blockPeriod))) * blt.feePerBlockPeriod
32+
return fee, nil
33+
}
Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
package fee
2+
3+
import (
4+
"reflect"
5+
"testing"
6+
7+
"github.com/zoobc/zoobc-core/common/constant"
8+
9+
"github.com/zoobc/zoobc-core/common/model"
10+
)
11+
12+
func TestBlockLifeTimeFeeModel_CalculateTxMinimumFee(t *testing.T) {
13+
type fields struct {
14+
blockPeriod int64
15+
feePerBlockPeriod int64
16+
}
17+
type args struct {
18+
txBody model.TransactionBodyInterface
19+
escrow *model.Escrow
20+
}
21+
tests := []struct {
22+
name string
23+
fields fields
24+
args args
25+
want int64
26+
wantErr bool
27+
}{
28+
{
29+
name: "CalculateTxMinimumFee-1",
30+
fields: fields{
31+
blockPeriod: 5,
32+
feePerBlockPeriod: constant.OneZBC / 100,
33+
},
34+
args: args{
35+
txBody: nil,
36+
escrow: &model.Escrow{
37+
Timeout: 17,
38+
},
39+
},
40+
want: 4 * (constant.OneZBC / 100),
41+
wantErr: false,
42+
},
43+
}
44+
for _, tt := range tests {
45+
t.Run(tt.name, func(t *testing.T) {
46+
blt := &BlockLifeTimeFeeModel{
47+
blockPeriod: tt.fields.blockPeriod,
48+
feePerBlockPeriod: tt.fields.feePerBlockPeriod,
49+
}
50+
got, err := blt.CalculateTxMinimumFee(tt.args.txBody, tt.args.escrow)
51+
if (err != nil) != tt.wantErr {
52+
t.Errorf("CalculateTxMinimumFee() error = %v, wantErr %v", err, tt.wantErr)
53+
return
54+
}
55+
if got != tt.want {
56+
t.Errorf("CalculateTxMinimumFee() got = %v, want %v", got, tt.want)
57+
}
58+
})
59+
}
60+
}
61+
62+
func TestNewBlockLifeTimeFeeModel(t *testing.T) {
63+
type args struct {
64+
blockPeriod int64
65+
feePerBlockPeriod int64
66+
}
67+
tests := []struct {
68+
name string
69+
args args
70+
want *BlockLifeTimeFeeModel
71+
}{
72+
{
73+
name: "NewBlockLifeTimeFeeModel-Success",
74+
args: args{
75+
blockPeriod: 0,
76+
feePerBlockPeriod: 0,
77+
},
78+
want: &BlockLifeTimeFeeModel{
79+
feePerBlockPeriod: 0,
80+
blockPeriod: 0,
81+
},
82+
},
83+
}
84+
for _, tt := range tests {
85+
t.Run(tt.name, func(t *testing.T) {
86+
if got := NewBlockLifeTimeFeeModel(tt.args.blockPeriod, tt.args.feePerBlockPeriod); !reflect.DeepEqual(got, tt.want) {
87+
t.Errorf("NewBlockLifeTimeFeeModel() = %v, want %v", got, tt.want)
88+
}
89+
})
90+
}
91+
}

common/fee/constantFeeModel.go

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
package fee
2+
3+
import "github.com/zoobc/zoobc-core/common/model"
4+
5+
type (
6+
// ConstantFeeModel is fee that'll be set as a constant number
7+
ConstantFeeModel struct {
8+
constantFee int64
9+
}
10+
)
11+
12+
func NewConstantFeeModel(constantFee int64) *ConstantFeeModel {
13+
return &ConstantFeeModel{
14+
constantFee: constantFee,
15+
}
16+
}
17+
18+
func (cfm *ConstantFeeModel) CalculateTxMinimumFee(
19+
model.TransactionBodyInterface, *model.Escrow,
20+
) (int64, error) {
21+
return cfm.constantFee, nil
22+
}

common/fee/fee.go

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
package fee
2+
3+
import "github.com/zoobc/zoobc-core/common/model"
4+
5+
type (
6+
FeeModelInterface interface {
7+
CalculateTxMinimumFee(txBody model.TransactionBodyInterface, escrow *model.Escrow) (int64, error)
8+
}
9+
)

0 commit comments

Comments
 (0)