diff --git a/pkg/core/blockchain_test.go b/pkg/core/blockchain_test.go index d5b7b5db4..d73076ee0 100644 --- a/pkg/core/blockchain_test.go +++ b/pkg/core/blockchain_test.go @@ -587,7 +587,7 @@ func TestSubscriptions(t *testing.T) { blocks, err := bc.genBlocks(1) require.NoError(t, err) require.Eventually(t, func() bool { return len(blockCh) != 0 }, time.Second, 10*time.Millisecond) - assert.Empty(t, notificationCh) + assert.Len(t, notificationCh, 1) // validator bounty assert.Len(t, executionCh, 1) assert.Empty(t, txCh) @@ -598,6 +598,9 @@ func TestSubscriptions(t *testing.T) { aer := <-executionCh assert.Equal(t, b.Hash(), aer.TxHash) + notif := <-notificationCh + require.Equal(t, bc.UtilityTokenHash(), notif.ScriptHash) + script := io.NewBufBinWriter() emit.Bytes(script.BinWriter, []byte("yay!")) emit.Syscall(script.BinWriter, interopnames.SystemRuntimeNotify) @@ -665,9 +668,12 @@ func TestSubscriptions(t *testing.T) { } } assert.Empty(t, txCh) - assert.Empty(t, notificationCh) + assert.Len(t, notificationCh, 1) assert.Empty(t, executionCh) + notif = <-notificationCh + require.Equal(t, bc.UtilityTokenHash(), notif.ScriptHash) + bc.UnsubscribeFromBlocks(blockCh) bc.UnsubscribeFromTransactions(txCh) bc.UnsubscribeFromNotifications(notificationCh) diff --git a/pkg/core/native/native_neo.go b/pkg/core/native/native_neo.go index 277594215..8e0185a8a 100644 --- a/pkg/core/native/native_neo.go +++ b/pkg/core/native/native_neo.go @@ -179,10 +179,22 @@ func (n *NEO) Initialize(ic *interop.Context) error { // OnPersist implements Contract interface. func (n *NEO) OnPersist(ic *interop.Context) error { + gas, err := n.GetGASPerBlock(ic, ic.Block.Index) + if err != nil { + return err + } + pubs, err := n.GetCommitteeMembers(ic.Chain, ic.DAO) + if err != nil { + return err + } + index := int(ic.Block.Index) % len(ic.Chain.GetConfig().StandbyCommittee) + gas.Mul(gas, big.NewInt(committeeRewardRatio)) + n.GAS.mint(ic, pubs[index].GetScriptHash(), gas.Div(gas, big.NewInt(100))) + if !n.votesChanged.Load().(bool) { return nil } - pubs, err := n.GetValidatorsInternal(ic.Chain, ic.DAO) + pubs, err = n.GetValidatorsInternal(ic.Chain, ic.DAO) if err != nil { return err } diff --git a/pkg/core/native_neo_test.go b/pkg/core/native_neo_test.go index f8017a877..9917123ee 100644 --- a/pkg/core/native_neo_test.go +++ b/pkg/core/native_neo_test.go @@ -14,6 +14,7 @@ import ( "github.com/nspcc-dev/neo-go/pkg/smartcontract/trigger" "github.com/nspcc-dev/neo-go/pkg/util" "github.com/nspcc-dev/neo-go/pkg/vm" + "github.com/nspcc-dev/neo-go/pkg/vm/opcode" "github.com/stretchr/testify/require" ) @@ -29,9 +30,10 @@ func TestNEO_Vote(t *testing.T) { defer bc.Close() neo := bc.contracts.NEO - tx := transaction.New(netmode.UnitTestNet, []byte{}, 0) + tx := transaction.New(netmode.UnitTestNet, []byte{byte(opcode.PUSH1)}, 0) ic := bc.newInteropContext(trigger.System, bc.dao, nil, tx) ic.VM = vm.New() + ic.Block = bc.newBlock(tx) standBySorted := bc.GetStandByValidators() sort.Sort(standBySorted) @@ -193,3 +195,26 @@ func TestNEO_CalculateBonus(t *testing.T) { }) } + +func TestNEO_CommitteeBountyOnPersist(t *testing.T) { + bc := newTestChain(t) + defer bc.Close() + + hs := make([]util.Uint160, testchain.CommitteeSize()) + for i := range hs { + hs[i] = testchain.PrivateKeyByID(i).GetScriptHash() + } + + bs := make(map[int]int64) + checkBalances := func() { + for i := 0; i < testchain.CommitteeSize(); i++ { + require.EqualValues(t, bs[i], bc.GetUtilityTokenBalance(hs[i]).Int64()) + } + } + + for i := 0; i < testchain.CommitteeSize()*2; i++ { + require.NoError(t, bc.AddBlock(bc.newBlock())) + bs[(i+1)%testchain.CommitteeSize()] += 25000000 + checkBalances() + } +} diff --git a/pkg/rpc/server/server_test.go b/pkg/rpc/server/server_test.go index eb2bc89c7..4f7be0b24 100644 --- a/pkg/rpc/server/server_test.go +++ b/pkg/rpc/server/server_test.go @@ -980,12 +980,12 @@ func testRPCProtocol(t *testing.T, doRPCCall func(string, string, *testing.T) [] require.NoError(t, json.Unmarshal(res, actual)) checkNep5TransfersAux(t, e, actual, sent, rcvd) } - t.Run("time frame only", func(t *testing.T) { testNEP5T(t, 4, 5, 0, 0, []int{3, 4, 5, 6}, []int{0, 1}) }) + t.Run("time frame only", func(t *testing.T) { testNEP5T(t, 4, 5, 0, 0, []int{3, 4, 5, 6}, []int{1, 2}) }) t.Run("no res", func(t *testing.T) { testNEP5T(t, 100, 100, 0, 0, []int{}, []int{}) }) - t.Run("limit", func(t *testing.T) { testNEP5T(t, 1, 7, 3, 0, []int{0, 1, 2}, []int{}) }) - t.Run("limit 2", func(t *testing.T) { testNEP5T(t, 4, 5, 2, 0, []int{3}, []int{0}) }) - t.Run("limit with page", func(t *testing.T) { testNEP5T(t, 1, 7, 3, 1, []int{3, 4}, []int{0}) }) - t.Run("limit with page 2", func(t *testing.T) { testNEP5T(t, 1, 7, 3, 2, []int{5, 6}, []int{1}) }) + t.Run("limit", func(t *testing.T) { testNEP5T(t, 1, 7, 3, 0, []int{0, 1}, []int{0}) }) + t.Run("limit 2", func(t *testing.T) { testNEP5T(t, 4, 5, 2, 0, []int{3}, []int{1}) }) + t.Run("limit with page", func(t *testing.T) { testNEP5T(t, 1, 7, 3, 1, []int{2, 3}, []int{1}) }) + t.Run("limit with page 2", func(t *testing.T) { testNEP5T(t, 1, 7, 3, 2, []int{4, 5}, []int{2}) }) }) } @@ -1075,7 +1075,7 @@ func checkNep5Balances(t *testing.T, e *executor, acc interface{}) { }, { Asset: e.chain.UtilityTokenHash(), - Amount: "799.09495030", + Amount: "799.34495030", LastUpdated: 7, }}, Address: testchain.PrivateKeyByID(0).GetScriptHash().StringLE(), @@ -1085,7 +1085,7 @@ func checkNep5Balances(t *testing.T, e *executor, acc interface{}) { } func checkNep5Transfers(t *testing.T, e *executor, acc interface{}) { - checkNep5TransfersAux(t, e, acc, []int{0, 1, 2, 3, 4, 5, 6, 7, 8}, []int{0, 1, 2, 3}) + checkNep5TransfersAux(t, e, acc, []int{0, 1, 2, 3, 4, 5, 6, 7, 8}, []int{0, 1, 2, 3, 4, 5, 6}) } func checkNep5TransfersAux(t *testing.T, e *executor, acc interface{}, sent, rcvd []int) { @@ -1103,6 +1103,7 @@ func checkNep5TransfersAux(t *testing.T, e *executor, acc interface{}, sent, rcv require.NoError(t, err) require.Equal(t, 1, len(blockSendRubles.Transactions)) txSendRubles := blockSendRubles.Transactions[0] + blockGASBounty := blockSendRubles // index 6 = size of committee blockReceiveRubles, err := e.chain.GetBlock(e.chain.GetHeaderHash(5)) require.NoError(t, err) @@ -1214,6 +1215,15 @@ func checkNep5TransfersAux(t *testing.T, e *executor, acc interface{}, sent, rcv }, }, Received: []result.NEP5Transfer{ + { + Timestamp: blockGASBounty.Timestamp, + Asset: e.chain.UtilityTokenHash(), + Address: "", + Amount: "0.25000000", + Index: 6, + NotifyIndex: 0, + TxHash: blockGASBounty.Hash(), + }, { Timestamp: blockReceiveRubles.Timestamp, Asset: rublesHash,