Skip to content

Commit 844f380

Browse files
authored
IOTEX-270 Improve rewarding protocol (iotexproject#593)
1 parent 53585a0 commit 844f380

File tree

8 files changed

+151
-56
lines changed

8 files changed

+151
-56
lines changed

action/protocol/execution/evm/evm.go

+3-11
Original file line numberDiff line numberDiff line change
@@ -11,15 +11,14 @@ import (
1111
"math"
1212
"math/big"
1313

14-
"github.com/iotexproject/iotex-core/action/protocol/rewarding"
15-
1614
"github.com/ethereum/go-ethereum/common"
1715
"github.com/ethereum/go-ethereum/core/vm"
1816
"github.com/ethereum/go-ethereum/params"
1917
"github.com/pkg/errors"
2018

2119
"github.com/iotexproject/iotex-core/action"
2220
"github.com/iotexproject/iotex-core/action/protocol"
21+
"github.com/iotexproject/iotex-core/action/protocol/rewarding"
2322
"github.com/iotexproject/iotex-core/address"
2423
"github.com/iotexproject/iotex-core/pkg/log"
2524
)
@@ -38,13 +37,6 @@ func MakeTransfer(db vm.StateDB, fromHash, toHash common.Address, amount *big.In
3837
db.AddBalance(toHash, amount)
3938
}
4039

41-
const (
42-
// FailureStatus is the status that contract execution failed
43-
FailureStatus = uint64(0)
44-
// SuccessStatus is the status that contract execution success
45-
SuccessStatus = uint64(1)
46-
)
47-
4840
// Params is the context and parameters
4941
type Params struct {
5042
context vm.Context
@@ -161,9 +153,9 @@ func ExecuteContract(
161153
ContractAddress: contractAddress,
162154
}
163155
if err != nil {
164-
receipt.Status = FailureStatus
156+
receipt.Status = action.FailureReceiptStatus
165157
} else {
166-
receipt.Status = SuccessStatus
158+
receipt.Status = action.SuccessReceiptStatus
167159
}
168160
if remainingGas > 0 {
169161
*raCtx.GasLimit += remainingGas

action/protocol/rewarding/admin.go

+18-18
Original file line numberDiff line numberDiff line change
@@ -22,18 +22,18 @@ import (
2222
// admin stores the admin data of the rewarding protocol
2323
type admin struct {
2424
admin address.Address
25-
BlockReward *big.Int
26-
EpochReward *big.Int
27-
NumDelegatesForEpochReward uint64
25+
blockReward *big.Int
26+
epochReward *big.Int
27+
numDelegatesForEpochReward uint64
2828
}
2929

3030
// Serialize serializes admin state into bytes
3131
func (a admin) Serialize() ([]byte, error) {
3232
gen := rewardingpb.Admin{
3333
Admin: a.admin.Bytes(),
34-
BlockReward: a.BlockReward.Bytes(),
35-
EpochReward: a.EpochReward.Bytes(),
36-
NumDelegatesForEpochReward: a.NumDelegatesForEpochReward,
34+
BlockReward: a.blockReward.Bytes(),
35+
EpochReward: a.epochReward.Bytes(),
36+
NumDelegatesForEpochReward: a.numDelegatesForEpochReward,
3737
}
3838
return proto.Marshal(&gen)
3939
}
@@ -48,9 +48,9 @@ func (a *admin) Deserialize(data []byte) error {
4848
if a.admin, err = address.FromBytes(gen.Admin); err != nil {
4949
return err
5050
}
51-
a.BlockReward = big.NewInt(0).SetBytes(gen.BlockReward)
52-
a.EpochReward = big.NewInt(0).SetBytes(gen.EpochReward)
53-
a.NumDelegatesForEpochReward = gen.NumDelegatesForEpochReward
51+
a.blockReward = big.NewInt(0).SetBytes(gen.BlockReward)
52+
a.epochReward = big.NewInt(0).SetBytes(gen.EpochReward)
53+
a.numDelegatesForEpochReward = gen.NumDelegatesForEpochReward
5454
return nil
5555
}
5656

@@ -79,9 +79,9 @@ func (p *Protocol) Initialize(
7979
adminKey,
8080
&admin{
8181
admin: adminAddr,
82-
BlockReward: blockReward,
83-
EpochReward: epochReward,
84-
NumDelegatesForEpochReward: numDelegatesForEpochReward,
82+
blockReward: blockReward,
83+
epochReward: epochReward,
84+
numDelegatesForEpochReward: numDelegatesForEpochReward,
8585
},
8686
); err != nil {
8787
return err
@@ -135,7 +135,7 @@ func (p *Protocol) BlockReward(
135135
if err := p.state(sm, adminKey, &a); err != nil {
136136
return nil, err
137137
}
138-
return a.BlockReward, nil
138+
return a.blockReward, nil
139139
}
140140

141141
// SetBlockReward sets the block reward amount for the block rewarding. Only the current admin could make this change
@@ -156,7 +156,7 @@ func (p *Protocol) EpochReward(
156156
if err := p.state(sm, adminKey, &a); err != nil {
157157
return nil, err
158158
}
159-
return a.EpochReward, nil
159+
return a.epochReward, nil
160160
}
161161

162162
// SetEpochReward sets the epoch reward amount shared by all beneficiaries in an epoch. Only the current admin could
@@ -178,7 +178,7 @@ func (p *Protocol) NumDelegatesForEpochReward(
178178
if err := p.state(sm, adminKey, &a); err != nil {
179179
return 0, err
180180
}
181-
return a.NumDelegatesForEpochReward, nil
181+
return a.numDelegatesForEpochReward, nil
182182
}
183183

184184
// SetNumDelegatesForEpochReward sets the number of candidates sharing an epoch reward
@@ -195,7 +195,7 @@ func (p *Protocol) SetNumDelegatesForEpochReward(
195195
if err := p.state(sm, adminKey, &a); err != nil {
196196
return err
197197
}
198-
a.NumDelegatesForEpochReward = num
198+
a.numDelegatesForEpochReward = num
199199
return p.putState(sm, adminKey, &a)
200200
}
201201

@@ -242,9 +242,9 @@ func (p *Protocol) setReward(
242242
return err
243243
}
244244
if blockLevel {
245-
a.BlockReward = amount
245+
a.blockReward = amount
246246
} else {
247-
a.EpochReward = amount
247+
a.epochReward = amount
248248
}
249249
return p.putState(sm, adminKey, &a)
250250
}

action/protocol/rewarding/fund.go

+5-4
Original file line numberDiff line numberDiff line change
@@ -53,10 +53,7 @@ func (p *Protocol) Deposit(
5353
sm protocol.StateManager,
5454
amount *big.Int,
5555
) error {
56-
raCtx, ok := protocol.GetRunActionsCtx(ctx)
57-
if !ok {
58-
log.S().Panic("Miss run action context")
59-
}
56+
raCtx := protocol.MustGetRunActionsCtx(ctx)
6057
if err := p.assertEnoughBalance(raCtx, sm, amount); err != nil {
6158
return err
6259
}
@@ -118,6 +115,10 @@ func (p *Protocol) assertEnoughBalance(
118115

119116
// DepositGas deposits gas into the rewarding fund
120117
func DepositGas(ctx context.Context, sm protocol.StateManager, amount *big.Int, registry *protocol.Registry) error {
118+
// If the gas fee is 0, return immediately
119+
if amount.Cmp(big.NewInt(0)) == 0 {
120+
return nil
121+
}
121122
// TODO: we bypass the gas deposit for the actions in genesis block. Later we should remove this after we remove
122123
// genesis actions
123124
raCtx := protocol.MustGetRunActionsCtx(ctx)

action/protocol/rewarding/protocol.go

+29-17
Original file line numberDiff line numberDiff line change
@@ -75,38 +75,44 @@ func (p *Protocol) Handle(
7575
case *action.SetReward:
7676
switch act.RewardType() {
7777
case action.BlockReward:
78+
si := sm.Snapshot()
7879
if err := p.SetBlockReward(ctx, sm, act.Amount()); err != nil {
79-
return p.settleAction(ctx, sm, 1), nil
80+
return p.settleAction(ctx, sm, action.FailureReceiptStatus, si)
8081
}
81-
return p.settleAction(ctx, sm, 0), nil
82+
return p.settleAction(ctx, sm, action.SuccessReceiptStatus, si)
8283
case action.EpochReward:
84+
si := sm.Snapshot()
8385
if err := p.SetEpochReward(ctx, sm, act.Amount()); err != nil {
84-
return p.settleAction(ctx, sm, 1), nil
86+
return p.settleAction(ctx, sm, action.FailureReceiptStatus, si)
8587
}
86-
return p.settleAction(ctx, sm, 0), nil
88+
return p.settleAction(ctx, sm, action.SuccessReceiptStatus, si)
8789
}
8890
case *action.DepositToRewardingFund:
91+
si := sm.Snapshot()
8992
if err := p.Deposit(ctx, sm, act.Amount()); err != nil {
90-
return p.settleAction(ctx, sm, 1), nil
93+
return p.settleAction(ctx, sm, action.FailureReceiptStatus, si)
9194
}
92-
return p.settleAction(ctx, sm, 0), nil
95+
return p.settleAction(ctx, sm, action.SuccessReceiptStatus, si)
9396
case *action.ClaimFromRewardingFund:
97+
si := sm.Snapshot()
9498
if err := p.Claim(ctx, sm, act.Amount()); err != nil {
95-
return p.settleAction(ctx, sm, 1), nil
99+
return p.settleAction(ctx, sm, action.FailureReceiptStatus, si)
96100
}
97-
return p.settleAction(ctx, sm, 0), nil
101+
return p.settleAction(ctx, sm, action.SuccessReceiptStatus, si)
98102
case *action.GrantReward:
99103
switch act.RewardType() {
100104
case action.BlockReward:
105+
si := sm.Snapshot()
101106
if err := p.GrantBlockReward(ctx, sm); err != nil {
102-
return p.settleAction(ctx, sm, 1), nil
107+
return p.settleAction(ctx, sm, action.FailureReceiptStatus, si)
103108
}
104-
return p.settleAction(ctx, sm, 0), nil
109+
return p.settleAction(ctx, sm, action.SuccessReceiptStatus, si)
105110
case action.EpochReward:
111+
si := sm.Snapshot()
106112
if err := p.GrantEpochReward(ctx, sm); err != nil {
107-
return p.settleAction(ctx, sm, 1), nil
113+
return p.settleAction(ctx, sm, action.FailureReceiptStatus, si)
108114
}
109-
return p.settleAction(ctx, sm, 0), nil
115+
return p.settleAction(ctx, sm, action.SuccessReceiptStatus, si)
110116
}
111117
}
112118
return nil, nil
@@ -166,16 +172,22 @@ func (p *Protocol) settleAction(
166172
ctx context.Context,
167173
sm protocol.StateManager,
168174
status uint64,
169-
) *action.Receipt {
175+
si int,
176+
) (*action.Receipt, error) {
170177
raCtx := protocol.MustGetRunActionsCtx(ctx)
178+
if status == action.FailureReceiptStatus {
179+
if err := sm.Revert(si); err != nil {
180+
return nil, err
181+
}
182+
}
171183
gasFee := big.NewInt(0).Mul(raCtx.GasPrice, big.NewInt(0).SetUint64(raCtx.IntrinsicGas))
172184
if err := DepositGas(ctx, sm, gasFee, raCtx.Registry); err != nil {
173-
p.createReceipt(1, raCtx.ActionHash, raCtx.IntrinsicGas)
185+
return nil, err
174186
}
175187
if err := p.increaseNonce(sm, raCtx.Caller, raCtx.Nonce); err != nil {
176-
return p.createReceipt(1, raCtx.ActionHash, raCtx.IntrinsicGas)
188+
return nil, err
177189
}
178-
return p.createReceipt(status, raCtx.ActionHash, raCtx.IntrinsicGas)
190+
return p.createReceipt(status, raCtx.ActionHash, raCtx.IntrinsicGas), nil
179191
}
180192

181193
func (p *Protocol) increaseNonce(sm protocol.StateManager, addr address.Address, nonce uint64) error {
@@ -194,7 +206,7 @@ func (p *Protocol) createReceipt(status uint64, actHash hash.Hash256, gasConsume
194206
// TODO: need to review the fields
195207
return &action.Receipt{
196208
ReturnValue: nil,
197-
Status: 0,
209+
Status: status,
198210
ActHash: actHash,
199211
GasConsumed: gasConsumed,
200212
ContractAddress: p.addr.String(),

action/protocol/rewarding/protocol_test.go

+72-1
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,10 @@ import (
1111
"math/big"
1212
"testing"
1313

14+
"github.com/iotexproject/iotex-core/action"
15+
16+
"github.com/iotexproject/iotex-core/test/identityset"
17+
1418
"github.com/iotexproject/iotex-core/blockchain/genesis"
1519

1620
"github.com/golang/mock/gomock"
@@ -57,6 +61,10 @@ func testProtocol(t *testing.T, test func(*testing.T, context.Context, factory.F
5761
Address: testaddress.Addrinfo["charlie"].String(),
5862
Votes: unit.ConvertIotxToRau(1000000),
5963
},
64+
{
65+
Address: testaddress.Addrinfo["delta"].String(),
66+
Votes: unit.ConvertIotxToRau(500000),
67+
},
6068
}, nil).AnyTimes()
6169
p := NewProtocol(chain, genesis.Default.NumDelegates, genesis.Default.NumSubEpochs)
6270

@@ -69,7 +77,7 @@ func testProtocol(t *testing.T, test func(*testing.T, context.Context, factory.F
6977
)
7078
ws, err := stateDB.NewWorkingSet()
7179
require.NoError(t, err)
72-
require.NoError(t, p.Initialize(ctx, ws, testaddress.Addrinfo["alfa"], big.NewInt(0), big.NewInt(10), big.NewInt(100), 10))
80+
require.NoError(t, p.Initialize(ctx, ws, testaddress.Addrinfo["alfa"], big.NewInt(0), big.NewInt(10), big.NewInt(100), 4))
7381
require.NoError(t, stateDB.Commit(ws))
7482

7583
ctx = protocol.WithRunActionsCtx(
@@ -108,3 +116,66 @@ func testProtocol(t *testing.T, test func(*testing.T, context.Context, factory.F
108116

109117
test(t, ctx, stateDB, p)
110118
}
119+
120+
func TestProtocol_Handle(t *testing.T) {
121+
ctrl := gomock.NewController(t)
122+
defer ctrl.Finish()
123+
124+
cfg := config.Default
125+
stateDB, err := factory.NewStateDB(cfg, factory.InMemStateDBOption())
126+
require.NoError(t, err)
127+
require.NoError(t, stateDB.Start(context.Background()))
128+
defer func() {
129+
require.NoError(t, stateDB.Stop(context.Background()))
130+
}()
131+
chain := mock_chainmanager.NewMockChainManager(ctrl)
132+
p := NewProtocol(chain, genesis.Default.NumDelegates, genesis.Default.NumSubEpochs)
133+
134+
ctx := protocol.WithRunActionsCtx(
135+
context.Background(),
136+
protocol.RunActionsCtx{
137+
BlockHeight: 0,
138+
},
139+
)
140+
ws, err := stateDB.NewWorkingSet()
141+
require.NoError(t, err)
142+
require.NoError(t, p.Initialize(
143+
ctx,
144+
ws,
145+
identityset.Address(0),
146+
big.NewInt(1000000),
147+
big.NewInt(10),
148+
big.NewInt(100),
149+
10,
150+
))
151+
require.NoError(t, stateDB.Commit(ws))
152+
153+
ws, err = stateDB.NewWorkingSet()
154+
require.NoError(t, err)
155+
gb := action.GrantRewardBuilder{}
156+
grant := gb.SetRewardType(action.BlockReward).Build()
157+
eb := action.EnvelopeBuilder{}
158+
e := eb.SetNonce(0).
159+
SetGasPrice(big.NewInt(0)).
160+
SetGasLimit(grant.GasLimit()).
161+
SetAction(&grant).
162+
Build()
163+
se, err := action.Sign(e, identityset.PrivateKey(0))
164+
require.NoError(t, err)
165+
ctx = protocol.WithRunActionsCtx(
166+
context.Background(),
167+
protocol.RunActionsCtx{
168+
Producer: identityset.Address(0),
169+
Caller: identityset.Address(0),
170+
BlockHeight: genesis.Default.NumDelegates * genesis.Default.NumSubEpochs,
171+
GasPrice: big.NewInt(0),
172+
},
173+
)
174+
receipt, err := p.Handle(ctx, se.Action(), ws)
175+
require.NoError(t, err)
176+
assert.Equal(t, action.SuccessReceiptStatus, receipt.Status)
177+
// Grant the block reward again should fail
178+
receipt, err = p.Handle(ctx, se.Action(), ws)
179+
require.NoError(t, err)
180+
assert.Equal(t, action.FailureReceiptStatus, receipt.Status)
181+
}

0 commit comments

Comments
 (0)