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 15, 2024
1 parent bfc3aa6 commit e325924
Show file tree
Hide file tree
Showing 3 changed files with 107 additions and 0 deletions.
47 changes: 47 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,11 +429,54 @@ 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).

// Extract previous committee public keys for comparison
prevCommitteePublicKeys := make([]*keys.PublicKey, len(cache.committee))
for i, member := range cache.committee {
pub, err := member.PublicKey()
if err != nil {
return fmt.Errorf("failed to get public key: %w", err)
}
prevCommitteePublicKeys[i] = pub
}
// Prepare for potential committee change
cache.nextValidators = cache.newEpochNextValidators
cache.committee = cache.newEpochCommittee
cache.committeeHash = cache.newEpochCommitteeHash
cache.votesChanged = false

// Extract new committee public keys for comparison
newCommitteePublicKeys := make([]*keys.PublicKey, len(cache.committee))
for i, member := range cache.committee {
pub, err := member.PublicKey()
if err != nil {
return fmt.Errorf("failed to get public key: %w", err)
}
newCommitteePublicKeys[i] = pub
}
// Check if the committee has changed by comparing public keys directly
committeeChanged := len(prevCommitteePublicKeys) != len(newCommitteePublicKeys)
for i := 0; i < len(prevCommitteePublicKeys) && !committeeChanged; i++ {
if !prevCommitteePublicKeys[i].Equal(newCommitteePublicKeys[i]) {
committeeChanged = true
}
}

// Notify subscribers if the committee has changed
if committeeChanged {
publicKeysToStackItems := func(publicKeys []*keys.PublicKey) []stackitem.Item {
items := make([]stackitem.Item, len(publicKeys))
for i, pubKey := range publicKeys {
items[i] = stackitem.NewByteArray(pubKey.Bytes())
}
return items
}
prevCommitteeStackItems := publicKeysToStackItems(prevCommitteePublicKeys)
newCommitteeStackItems := publicKeysToStackItems(newCommitteePublicKeys)
ic.AddNotification(n.Hash, "CommitteeChanged", stackitem.NewArray([]stackitem.Item{
stackitem.NewArray(prevCommitteeStackItems), stackitem.NewArray(newCommitteeStackItems),
}))
}
// We need to put in storage anyway, as it affects dumps
ic.DAO.PutStorageItem(n.ID, prefixCommittee, cache.committee.Bytes(ic.DAO.GetItemCtx()))
}
Expand Down
54 changes: 54 additions & 0 deletions pkg/core/native/native_test/neo_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,60 @@ func TestNEO_CandidateEvents(t *testing.T) {
aer = e.GetTxExecResult(t, tx)
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)
validatorsCount := cfg.GetNumOfCNs(0)
freq := validatorsCount + committeeSize
advanceChain := func(t *testing.T) {
for i := 0; i < freq-1; i++ {
neoCommitteeInvoker.AddNewBlock(t)
}
}
voters := make([]neotest.Signer, committeeSize+1)
candidates := make([]neotest.Signer, committeeSize+1)
for i := 0; i < committeeSize+1; 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*4-2)
for i := 0; i < committeeSize+1; i++ {
transferTx := neoValidatorsInvoker.PrepareInvoke(t, "transfer", e.Validator.ScriptHash(), voters[i].(neotest.SingleSigner).Account().PrivateKey().GetScriptHash(), int64(committeeSize+1-i)*1000000, nil)
txes = append(txes, transferTx)
if i > 0 {
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)
}
}
//for _, tx := range txes {
// e.CheckHalt(t, tx.Hash(), stackitem.Make(true))
//}
prevCommitteePublicKeys := make([]*keys.PublicKey, committeeSize)
for i, member := range neoCommitteeInvoker.Signers {
prevCommitteePublicKeys[i] = member.Script()

Check failure on line 156 in pkg/core/native/native_test/neo_test.go

View workflow job for this annotation

GitHub Actions / Coverage

cannot use member.Script() (value of type []byte) as *"github.com/nspcc-dev/neo-go/pkg/crypto/keys".PublicKey value in assignment

Check failure on line 156 in pkg/core/native/native_test/neo_test.go

View workflow job for this annotation

GitHub Actions / Run tests (ubuntu-22.04, 1.20)

cannot use member.Script() (value of type []byte) as *"github.com/nspcc-dev/neo-go/pkg/crypto/keys".PublicKey value in assignment

Check failure on line 156 in pkg/core/native/native_test/neo_test.go

View workflow job for this annotation

GitHub Actions / Run tests (ubuntu-22.04, 1.21)

cannot use member.Script() (value of type []byte) as *"github.com/nspcc-dev/neo-go/pkg/crypto/keys".PublicKey value in assignment

Check failure on line 156 in pkg/core/native/native_test/neo_test.go

View workflow job for this annotation

GitHub Actions / Run tests (windows-2022, 1.22)

cannot use member.Script() (value of type []byte) as *"github.com/nspcc-dev/neo-go/pkg/crypto/keys".PublicKey value in assignment

Check failure on line 156 in pkg/core/native/native_test/neo_test.go

View workflow job for this annotation

GitHub Actions / Run tests (macos-12, 1.22)

cannot use member.Script() (value of type []byte) as *"github.com/nspcc-dev/neo-go/pkg/crypto/keys".PublicKey value in assignment

Check failure on line 156 in pkg/core/native/native_test/neo_test.go

View workflow job for this annotation

GitHub Actions / Run tests (macos-14, 1.22)

cannot use member.Script() (value of type []byte) as *"github.com/nspcc-dev/neo-go/pkg/crypto/keys".PublicKey value in assignment
//member.(neotest.SingleSigner).Account().PublicKey()
}
advanceChain(t)
newCommitteePublicKeys := make([]*keys.PublicKey, committeeSize)
for i, member := range neoCommitteeInvoker.Signers {
newCommitteePublicKeys[i] = member.(neotest.SingleSigner).Account().PublicKey()
}
tx := neoCommitteeInvoker.WithSigners(candidates[0]).Invoke(t, true, "unregisterCandidate", candidates[0].(neotest.SingleSigner).Account().PublicKey().Bytes())
e.CheckTxNotificationEvent(t, tx, 0, state.NotificationEvent{
ScriptHash: neoCommitteeInvoker.Hash,
Name: "CommitteeChanged",
Item: stackitem.NewArray([]stackitem.Item{
stackitem.NewArray([]stackitem.Item{}),
stackitem.NewArray([]stackitem.Item{}),
}),
})
}

func TestNEO_Vote(t *testing.T) {
neoCommitteeInvoker := newNeoCommitteeClient(t, 100_0000_0000)
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

0 comments on commit e325924

Please sign in to comment.