forked from TrueCloudLab/neoneo-go
parent
502cdd68ab
commit
5e013311e6
3 changed files with 109 additions and 5 deletions
|
@ -240,6 +240,18 @@ func newNEO(cfg config.ProtocolConfiguration) *NEO {
|
|||
md = newMethodAndPrice(n.setRegisterPrice, 1<<15, callflag.States)
|
||||
n.AddMethod(md, desc)
|
||||
|
||||
n.AddEvent("CandidateStateChanged",
|
||||
manifest.NewParameter("pubkey", smartcontract.PublicKeyType),
|
||||
manifest.NewParameter("registered", smartcontract.BoolType),
|
||||
manifest.NewParameter("votes", smartcontract.IntegerType),
|
||||
)
|
||||
n.AddEvent("Vote",
|
||||
manifest.NewParameter("account", smartcontract.Hash160Type),
|
||||
manifest.NewParameter("from", smartcontract.PublicKeyType),
|
||||
manifest.NewParameter("to", smartcontract.PublicKeyType),
|
||||
manifest.NewParameter("amount", smartcontract.IntegerType),
|
||||
)
|
||||
|
||||
return n
|
||||
}
|
||||
|
||||
|
@ -733,6 +745,8 @@ func (n *NEO) registerCandidate(ic *interop.Context, args []stackitem.Item) stac
|
|||
|
||||
// RegisterCandidateInternal registers pub as a new candidate.
|
||||
func (n *NEO) RegisterCandidateInternal(ic *interop.Context, pub *keys.PublicKey) error {
|
||||
var emitEvent = true
|
||||
|
||||
key := makeValidatorKey(pub)
|
||||
si := ic.DAO.GetStorageItem(n.ID, key)
|
||||
var c *candidate
|
||||
|
@ -740,9 +754,18 @@ func (n *NEO) RegisterCandidateInternal(ic *interop.Context, pub *keys.PublicKey
|
|||
c = &candidate{Registered: true}
|
||||
} else {
|
||||
c = new(candidate).FromBytes(si)
|
||||
emitEvent = !c.Registered
|
||||
c.Registered = true
|
||||
}
|
||||
return putConvertibleToDAO(n.ID, ic.DAO, key, c)
|
||||
err := putConvertibleToDAO(n.ID, ic.DAO, key, c)
|
||||
if emitEvent {
|
||||
ic.AddNotification(n.Hash, "CandidateStateChanged", stackitem.NewArray([]stackitem.Item{
|
||||
stackitem.NewByteArray(pub.Bytes()),
|
||||
stackitem.NewBool(c.Registered),
|
||||
stackitem.NewBigInteger(&c.Votes),
|
||||
}))
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func (n *NEO) unregisterCandidate(ic *interop.Context, args []stackitem.Item) stackitem.Item {
|
||||
|
@ -759,6 +782,8 @@ func (n *NEO) unregisterCandidate(ic *interop.Context, args []stackitem.Item) st
|
|||
|
||||
// UnregisterCandidateInternal unregisters pub as a candidate.
|
||||
func (n *NEO) UnregisterCandidateInternal(ic *interop.Context, pub *keys.PublicKey) error {
|
||||
var err error
|
||||
|
||||
key := makeValidatorKey(pub)
|
||||
si := ic.DAO.GetStorageItem(n.ID, key)
|
||||
if si == nil {
|
||||
|
@ -767,12 +792,20 @@ func (n *NEO) UnregisterCandidateInternal(ic *interop.Context, pub *keys.PublicK
|
|||
cache := ic.DAO.GetRWCache(n.ID).(*NeoCache)
|
||||
cache.validators = nil
|
||||
c := new(candidate).FromBytes(si)
|
||||
emitEvent := c.Registered
|
||||
c.Registered = false
|
||||
ok := n.dropCandidateIfZero(ic.DAO, cache, pub, c)
|
||||
if ok {
|
||||
return nil
|
||||
if !ok {
|
||||
err = putConvertibleToDAO(n.ID, ic.DAO, key, c)
|
||||
}
|
||||
return putConvertibleToDAO(n.ID, ic.DAO, key, c)
|
||||
if emitEvent {
|
||||
ic.AddNotification(n.Hash, "CandidateStateChanged", stackitem.NewArray([]stackitem.Item{
|
||||
stackitem.NewByteArray(pub.Bytes()),
|
||||
stackitem.NewBool(c.Registered),
|
||||
stackitem.NewBigInteger(&c.Votes),
|
||||
}))
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func (n *NEO) vote(ic *interop.Context, args []stackitem.Item) stackitem.Item {
|
||||
|
@ -834,17 +867,33 @@ func (n *NEO) VoteInternal(ic *interop.Context, h util.Uint160, pub *keys.Public
|
|||
if err := n.ModifyAccountVotes(acc, ic.DAO, new(big.Int).Neg(&acc.Balance), false); err != nil {
|
||||
return err
|
||||
}
|
||||
oldVote := acc.VoteTo
|
||||
acc.VoteTo = pub
|
||||
if err := n.ModifyAccountVotes(acc, ic.DAO, &acc.Balance, true); err != nil {
|
||||
return err
|
||||
}
|
||||
ic.DAO.PutStorageItem(n.ID, key, acc.Bytes())
|
||||
|
||||
ic.AddNotification(n.Hash, "Vote", stackitem.NewArray([]stackitem.Item{
|
||||
stackitem.NewByteArray(h.BytesBE()),
|
||||
keyToStackItem(oldVote),
|
||||
keyToStackItem(pub),
|
||||
stackitem.NewBigInteger(&acc.Balance),
|
||||
}))
|
||||
|
||||
if newGas != nil { // Can be if it was already distributed in the same block.
|
||||
n.GAS.mint(ic, h, newGas, true)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func keyToStackItem(k *keys.PublicKey) stackitem.Item {
|
||||
if k == nil {
|
||||
return stackitem.Null{}
|
||||
}
|
||||
return stackitem.NewByteArray(k.Bytes())
|
||||
}
|
||||
|
||||
// ModifyAccountVotes modifies votes of the specified account by value (can be negative).
|
||||
// typ specifies if this modify is occurring during transfer or vote (with old or new validator).
|
||||
func (n *NEO) ModifyAccountVotes(acc *state.NEOBalance, d *dao.Simple, value *big.Int, isNewVote bool) error {
|
||||
|
|
|
@ -60,6 +60,61 @@ func TestNEO_RegisterPriceCache(t *testing.T) {
|
|||
testGetSetCache(t, newNeoCommitteeClient(t, 100_0000_0000), "RegisterPrice", native.DefaultRegisterPrice)
|
||||
}
|
||||
|
||||
func TestNEO_CandidateEvents(t *testing.T) {
|
||||
c := newNativeClient(t, nativenames.Neo)
|
||||
singleSigner := c.Signers[0].(neotest.MultiSigner).Single(0)
|
||||
cc := c.WithSigners(c.Signers[0], singleSigner)
|
||||
e := c.Executor
|
||||
pkb := singleSigner.Account().PrivateKey().PublicKey().Bytes()
|
||||
|
||||
// Register 1 -> event
|
||||
tx := cc.Invoke(t, true, "registerCandidate", pkb)
|
||||
e.CheckTxNotificationEvent(t, tx, 0, state.NotificationEvent{
|
||||
ScriptHash: c.Hash,
|
||||
Name: "CandidateStateChanged",
|
||||
Item: stackitem.NewArray([]stackitem.Item{
|
||||
stackitem.NewByteArray(pkb),
|
||||
stackitem.NewBool(true),
|
||||
stackitem.Make(0),
|
||||
}),
|
||||
})
|
||||
|
||||
// Register 2 -> no event
|
||||
tx = cc.Invoke(t, true, "registerCandidate", pkb)
|
||||
aer := e.GetTxExecResult(t, tx)
|
||||
require.Equal(t, 0, len(aer.Events))
|
||||
|
||||
// Vote -> event
|
||||
tx = c.Invoke(t, true, "vote", c.Signers[0].ScriptHash().BytesBE(), pkb)
|
||||
e.CheckTxNotificationEvent(t, tx, 0, state.NotificationEvent{
|
||||
ScriptHash: c.Hash,
|
||||
Name: "Vote",
|
||||
Item: stackitem.NewArray([]stackitem.Item{
|
||||
stackitem.NewByteArray(c.Signers[0].ScriptHash().BytesBE()),
|
||||
stackitem.Null{},
|
||||
stackitem.NewByteArray(pkb),
|
||||
stackitem.Make(100000000),
|
||||
}),
|
||||
})
|
||||
|
||||
// Unregister 1 -> event
|
||||
tx = cc.Invoke(t, true, "unregisterCandidate", pkb)
|
||||
e.CheckTxNotificationEvent(t, tx, 0, state.NotificationEvent{
|
||||
ScriptHash: c.Hash,
|
||||
Name: "CandidateStateChanged",
|
||||
Item: stackitem.NewArray([]stackitem.Item{
|
||||
stackitem.NewByteArray(pkb),
|
||||
stackitem.NewBool(false),
|
||||
stackitem.Make(100000000),
|
||||
}),
|
||||
})
|
||||
|
||||
// Unregister 2 -> no event
|
||||
tx = cc.Invoke(t, true, "unregisterCandidate", pkb)
|
||||
aer = e.GetTxExecResult(t, tx)
|
||||
require.Equal(t, 0, len(aer.Events))
|
||||
}
|
||||
|
||||
func TestNEO_Vote(t *testing.T) {
|
||||
neoCommitteeInvoker := newNeoCommitteeClient(t, 100_0000_0000)
|
||||
neoValidatorsInvoker := neoCommitteeInvoker.WithSigners(neoCommitteeInvoker.Validator)
|
||||
|
|
|
@ -75,7 +75,7 @@ const (
|
|||
nfsoContractHash = "5f9ebd6b001b54c7bc70f96e0412fcf415dfe09f"
|
||||
nfsoToken1ID = "7e244ffd6aa85fb1579d2ed22e9b761ab62e3486"
|
||||
invokescriptContractAVM = "VwIADBQBDAMOBQYMDQIODw0DDgcJAAAAAErZMCQE2zBwaEH4J+yMqiYEEUAMFA0PAwIJAAIBAwcDBAUCAQAOBgwJStkwJATbMHFpQfgn7IyqJgQSQBNA"
|
||||
block20StateRootLE = "0fbb19143cb782df2c893d448a89ec959bea8bf467faf747638975812d570f72"
|
||||
block20StateRootLE = "cda0adf452c190700f792bcac29973b85532b7c27192e96172cfa0c8acaa4f9e"
|
||||
)
|
||||
|
||||
var (
|
||||
|
|
Loading…
Reference in a new issue