Skip to content

Commit

Permalink
native: add committee change events
Browse files Browse the repository at this point in the history
Port neo-project/neo#3158.

Close #3326

Signed-off-by: Ekaterina Pavlova <ekt@morphbits.io>
  • Loading branch information
AliceInHunterland committed Mar 19, 2024
1 parent 7e12cc1 commit 2c86876
Show file tree
Hide file tree
Showing 5 changed files with 101 additions and 1 deletion.
14 changes: 14 additions & 0 deletions pkg/core/native/native_neo.go
Original file line number Diff line number Diff line change
Expand Up @@ -265,6 +265,10 @@ func newNEO(cfg config.ProtocolConfiguration) *NEO {
manifest.NewParameter("to", smartcontract.PublicKeyType),
manifest.NewParameter("amount", smartcontract.IntegerType),
)
n.AddEvent("CommitteeChanged",
manifest.NewParameter("old", smartcontract.ArrayType),
manifest.NewParameter("new", smartcontract.ArrayType),
)

return n
}
Expand Down Expand Up @@ -425,6 +429,16 @@ func (n *NEO) OnPersist(ic *interop.Context) error {
cache := ic.DAO.GetRWCache(n.ID).(*NeoCache)
// Cached newEpoch* values always have proper value set (either by PostPersist
// during the last epoch block handling or by initialization code).

for i := 0; i < len(cache.newEpochCommittee); i++ {
if cache.newEpochCommittee[i].Key != cache.committee[i].Key || len(cache.newEpochCommittee) != len(cache.committee) {
ic.AddNotification(n.Hash, "CommitteeChanged", stackitem.NewArray([]stackitem.Item{
cache.committee.toNotificationItem(), cache.newEpochCommittee.toNotificationItem(),
}))
break
}
}

cache.nextValidators = cache.newEpochNextValidators
cache.committee = cache.newEpochCommittee
cache.committeeHash = cache.newEpochCommitteeHash
Expand Down
70 changes: 70 additions & 0 deletions pkg/core/native/native_test/neo_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,76 @@ func TestNEO_CandidateEvents(t *testing.T) {
require.Equal(t, 0, len(aer.Events))
}

func TestNEO_CommitteeEvents(t *testing.T) {
neoCommitteeInvoker := newNeoCommitteeClient(t, 100_0000_0000)
neoValidatorsInvoker := neoCommitteeInvoker.WithSigners(neoCommitteeInvoker.Validator)
e := neoCommitteeInvoker.Executor

cfg := e.Chain.GetConfig()
committeeSize := cfg.GetCommitteeSize(0)

voters := make([]neotest.Signer, committeeSize)
candidates := make([]neotest.Signer, committeeSize)
for i := 0; i < committeeSize; i++ {
voters[i] = e.NewAccount(t, 10_0000_0000)
candidates[i] = e.NewAccount(t, 2000_0000_0000) // enough for one registration
}
txes := make([]*transaction.Transaction, 0, committeeSize*3)
for i := 0; i < committeeSize; i++ {
transferTx := neoValidatorsInvoker.PrepareInvoke(t, "transfer", e.Validator.ScriptHash(), voters[i].(neotest.SingleSigner).Account().PrivateKey().GetScriptHash(), int64(committeeSize-i)*1000000, nil)
txes = append(txes, transferTx)

registerTx := neoValidatorsInvoker.WithSigners(candidates[i]).PrepareInvoke(t, "registerCandidate", candidates[i].(neotest.SingleSigner).Account().PublicKey().Bytes())
txes = append(txes, registerTx)

voteTx := neoValidatorsInvoker.WithSigners(voters[i]).PrepareInvoke(t, "vote", voters[i].(neotest.SingleSigner).Account().PrivateKey().GetScriptHash(), candidates[i].(neotest.SingleSigner).Account().PublicKey().Bytes())
txes = append(txes, voteTx)
}
block := neoValidatorsInvoker.AddNewBlock(t, txes...)
for _, tx := range txes {
e.CheckHalt(t, tx.Hash(), stackitem.Make(true))
}

// Advance the chain to trigger committee recalculation and potential change.
for (block.Index)%uint32(committeeSize) != 0 {
block = neoCommitteeInvoker.AddNewBlock(t)
}
expectedNewCommitteeStackItems := make([]stackitem.Item, 0, committeeSize)
for _, candidate := range candidates {
expectedNewCommitteeStackItems = append(expectedNewCommitteeStackItems, stackitem.NewByteArray(candidate.(neotest.SingleSigner).Account().PublicKey().Bytes()))
}
expectedOldCommitteePublicKeys, err := keys.NewPublicKeysFromStrings(cfg.StandbyCommittee)
require.NoError(t, err)
expectedOldCommitteeStackItems := make([]stackitem.Item, len(expectedOldCommitteePublicKeys))
for i, pubKey := range expectedOldCommitteePublicKeys {
expectedOldCommitteeStackItems[i] = stackitem.NewByteArray(pubKey.Bytes())
}
// Check for CommitteeChanged event in the last persisted block's AER.
blockHash := e.Chain.CurrentBlockHash()
aer, err := e.Chain.GetAppExecResults(blockHash, trigger.OnPersist)
require.NoError(t, err)
require.Equal(t, 1, len(aer))

found := false
for _, event := range aer[0].Events {
if event.Name == "CommitteeChanged" {
require.Equal(t, 2, len(event.Item.Value().([]stackitem.Item)))

oldCommitteeStackItem := event.Item.Value().([]stackitem.Item)[0].(*stackitem.Array)
for i, item := range oldCommitteeStackItem.Value().([]stackitem.Item) {
require.Equal(t, expectedOldCommitteeStackItems[i].(*stackitem.ByteArray).Value().([]byte), item.Value().([]byte))
}
newCommitteeStackItem := event.Item.Value().([]stackitem.Item)[1].(*stackitem.Array)
for i, item := range newCommitteeStackItem.Value().([]stackitem.Item) {
require.Equal(t, expectedNewCommitteeStackItems[i].(*stackitem.ByteArray).Value().([]byte), item.Value().([]byte))
}
found = true
break
}
}
require.True(t, found, "CommitteeChanged event not found")
}

func TestNEO_Vote(t *testing.T) {
neoCommitteeInvoker := newNeoCommitteeClient(t, 100_0000_0000)
neoValidatorsInvoker := neoCommitteeInvoker.WithSigners(neoCommitteeInvoker.Validator)
Expand Down
10 changes: 10 additions & 0 deletions pkg/core/native/neo_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,16 @@ func (k keysWithVotes) toStackItem() stackitem.Item {
return stackitem.NewArray(arr)
}

// toNotificationItem converts keysWithVotes to a stackitem.Item suitable for use in a notification,
// including public keys only.
func (k keysWithVotes) toNotificationItem() stackitem.Item {
arr := make([]stackitem.Item, len(k))
for i := range k {
arr[i] = stackitem.NewByteArray([]byte(k[i].Key))
}
return stackitem.NewArray(arr)
}

func (k *keysWithVotes) fromStackItem(item stackitem.Item) error {
arr, ok := item.Value().([]stackitem.Item)
if !ok {
Expand Down
6 changes: 6 additions & 0 deletions pkg/rpcclient/neo/neo.go
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,12 @@ type CandidateStateEvent struct {
Votes *big.Int
}

// CommitteeChangedEvent represents a CommitteeChanged NEO event.
type CommitteeChangedEvent struct {
Old []keys.PublicKey
New []keys.PublicKey
}

// VoteEvent represents a Vote NEO event.
type VoteEvent struct {
Account util.Uint160
Expand Down
2 changes: 1 addition & 1 deletion pkg/services/rpcsrv/server_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,7 @@ const (
faultedTxHashLE = "82279bfe9bada282ca0f8cb8e0bb124b921af36f00c69a518320322c6f4fef60"
faultedTxBlock uint32 = 23
invokescriptContractAVM = "VwIADBQBDAMOBQYMDQIODw0DDgcJAAAAAErZMCQE2zBwaEH4J+yMqiYEEUAMFA0PAwIJAAIBAwcDBAUCAQAOBgwJStkwJATbMHFpQfgn7IyqJgQSQBNA"
block20StateRootLE = "858c873539d6d24a70f2be13f9dafc61aef2b63c2aa16bb440676de6e44e3cf1"
block20StateRootLE = "397c69adbc0201d59623fa913bfff4a2da25c792c484d1d278c061709f2c21cf"
)

var (
Expand Down

0 comments on commit 2c86876

Please sign in to comment.