-
Notifications
You must be signed in to change notification settings - Fork 17
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
feat/Make NewEpoch
callback mechanism more generic
#368
Conversation
dc252aa
to
7a601b0
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Tests fail.
7a601b0
to
2bebea7
Compare
2bebea7
to
0623894
Compare
Ready one more time. Look carefully, please. |
0623894
to
3cbdba1
Compare
// callback requester. Netmap contract's address is taken from the | ||
// NNS contract, therefore, it must be presented and filled with | ||
// netmap information for a correct SubscribeForNewEpoch call; otherwise | ||
// a successive call is not guaranteed. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
what call is this line talking about? not guaranteed
seems like some kind of random
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
what call is this line talking about?
method call
not guaranteed seems like some kind of random
i meant it depends on an NNS implementation. it may and may not panic
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
i've read this doc several times and not sure i completely understand it. We impose some preconditions (Netmap contract registered in NNS). If complied with - success, otherwise panic, right? Where is not guaranteed
come from?
filled with netmap information
- who must be filled and what information?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If complied with - success, otherwise panic, right?
well, to me that is not for sure. you need this to work it OK, but if it is not true, it depends on the NNS contract implementation. this call maybe a part of transaction, and panic (exception) may fail the whole TX
Where is not guaranteed come from?
that is how i said "undefined behavior" but that time i wanted to say it this way
filled with netmap information - who must be filled and what information?
NNS contract
// NNS contract, therefore, it must be presented and filled with | ||
// netmap information for a correct SubscribeForNewEpoch call; otherwise | ||
// a successive call is not guaranteed. | ||
// Caller must have `NewEpoch` method with a single numeric argument. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
possible to check?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@roman-khimov, no args' types check?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It doesn't care even for actual calls (hi, neo-project/neo#1891) and you want it to check a complete signature in hasMethod
...
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done
"github.com/nspcc-dev/neo-go/pkg/interop/native/std" | ||
) | ||
|
||
// ResolveContractHash resolves contract hash by its well-known NeoFS name. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
well known by whom?
// ResolveContractHash resolves contract hash by its well-known NeoFS name. | |
// ResolveContractHash hash of the NeoFS contract by its NNS domain name. |
btw is there any place where we doc these names?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ResolveContractHash hash of the NeoFS contract
what do you want to say by it?
by its NNS domain name.
not sure we can say it. that is not the full NNS name, a caller should pass just container
, not container.neofs
) | ||
|
||
// ResolveContractHash resolves contract hash by its well-known NeoFS name. | ||
// Contract name should be lowercased, should not include `.neofs` TLD. Example |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
its better to either require name from the names list (rel thread above) or just should be a valid NNS domain
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
its better to either require name from the names list (rel thread above)
the list can grow and docs arent updated usually
should be a valid NNS domain
but container
is not a valid NNS name
// values: "netmap", "container", etc. | ||
// Relies on some NeoFS specifics: | ||
// 1. NNS contract should be deployed first (and should have `1` contract ID) | ||
// 2. It should be prefilled with contract hashes by their names (no |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
isnt this obvious for ResolveContractHash
semantics? If it's not prefilled -> resolving fails
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
NNS is kinda general thing and we are not the only ones who have it. so i wanted to highlight what exactly should be done: NNS is deployed and it should map string
-> uint160
(although i understand that the only callers of this method is are our contracts)
netmap/netmap_contract.go
Outdated
@@ -73,7 +73,8 @@ const ( | |||
containerContractKey = "containerScriptHash" | |||
balanceContractKey = "balanceScriptHash" | |||
|
|||
cleanupEpochMethod = "newEpoch" | |||
newEpochSubscribersKey = "newEpochSubscribers" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
newEpochSubscribersKey = "newEpochSubscribers" | |
newEpochSubscribersKeyPrefix = "newEpochSubscribers" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please use one byte prefixes, they don't have to be this long and we can only have 64-byte keys.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
newEpochSubscribersKeyPrefix
ok but without key
then
Please use one byte prefixes
n
won my democratic election
// contracts are migrated in alphabetical order at least for now | ||
|
||
contract.SeekStorage(append(newEpochSubsNewPrefix, 0), func(k, v []byte) bool { | ||
balanceGot, err := util.Uint160DecodeBytesLE(k) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
u dont check func entrance. I'd gather map index->address and check after SeekStorage
call
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
fixed by bool flags
netmap/netmap_contract.go
Outdated
@@ -601,6 +605,32 @@ func ListConfig() []record { | |||
return config | |||
} | |||
|
|||
// SubscribeForNewEpoch registers passed contract as a NewEpoch event | |||
// subscriber. Such a contract must have a `NewEpoch` method with a single | |||
// numeric argument. Transactions that call SubscribeForNewEpoch must be |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
// numeric argument. Transactions that call SubscribeForNewEpoch must be | |
// numeric parameter. Transactions that call SubscribeForNewEpoch must be |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
fixed
netmap/netmap_contract.go
Outdated
// subscriber. Such a contract must have a `NewEpoch` method with a single | ||
// numeric argument. Transactions that call SubscribeForNewEpoch must be | ||
// witnessed by the Alphabet. | ||
// Produces `NewEpochHookRegistration` notification event with a just |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
according to code it is
// Produces `NewEpochHookRegistration` notification event with a just | |
// Produces `NewEpochSubscription` notification event with a just |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
fixed. it did not live renamings well
tests/migration/storage.go
Outdated
@@ -252,6 +252,13 @@ func (x *Contract) GetStorageItem(key []byte) []byte { | |||
return x.exec.Chain.GetStorageItem(x.id, key) | |||
} | |||
|
|||
// SeekStorage calls a provided handler against every stored item that starts | |||
// with a provided prefix. On handler's `false` return stops iteration. prefix | |||
// is removed from the resulting pair. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
// is removed from the resulting pair. | |
// is removed from the resulting pair key. |
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
fixed
1st commit message has strange quotes |
// NNS contract, therefore, it must be presented and filled with | ||
// netmap information for a correct SubscribeForNewEpoch call; otherwise | ||
// a successive call is not guaranteed. | ||
// Caller must have `NewEpoch` method with a single numeric argument. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
netmap/netmap_contract.go
Outdated
@@ -73,7 +73,8 @@ const ( | |||
containerContractKey = "containerScriptHash" | |||
balanceContractKey = "balanceScriptHash" | |||
|
|||
cleanupEpochMethod = "newEpoch" | |||
newEpochSubscribersKey = "newEpochSubscribers" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please use one byte prefixes, they don't have to be this long and we can only have 64-byte keys.
3cbdba1
to
b016c50
Compare
fixed |
b016c50
to
2957a7e
Compare
2957a7e
to
0f80410
Compare
common/netmap.go
Outdated
@@ -12,6 +14,11 @@ import ( | |||
// a successive call is not guaranteed. | |||
// Caller must have `NewEpoch` method with a single numeric argument. | |||
func SubscribeForNewEpoch() { | |||
callingHash := runtime.GetExecutingScriptHash() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's executing script hash and you're calling it calling
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
i meant that is a contract that called that method. renamed to callingContract
, it is ok?
common/netmap.go
Outdated
@@ -12,6 +14,11 @@ import ( | |||
// a successive call is not guaranteed. | |||
// Caller must have `NewEpoch` method with a single numeric argument. | |||
func SubscribeForNewEpoch() { | |||
callingHash := runtime.GetExecutingScriptHash() | |||
if !management.HasMethod(callingHash, "newEpoch", 1) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why this check is here and not in the subscribeForNewEpoch
itself? It makes much more sense there since netmap
controls its state and shouldn't allow bad subscriptions (forget contract upgrades for a moment).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
moved to the netmap contract
0f80410
to
2d8df56
Compare
b34ad43
to
c7dae34
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM otherwise, but these are minor comments and may be left unresolved.
it := storage.Find(ctx, newEpochSubscribersPrefix, storage.RemovePrefix|storage.KeysOnly) | ||
for iterator.Next(it) { | ||
contractHash := interop.Hash160(iterator.Value(it).([]byte)[1:]) // one byte is for number prefix | ||
contract.Call(contractHash, cleanupEpochMethod, contract.All, epoch) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
And one more important moment that just came to my mind. If something (panic, I mean) happens in the calling callback, then the rest of callbacks won't be executed. It remains PostPersist
and technically it's OK to fail immediately, so just a question: do we need to think about some exception handlers here?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
do we need to think about some exception handlers here?
only our own contracts are expected to be new-epoch-notified so any panic is a global panic to me and i can not say that some contract is more or less important to us, we need all of them to be notified. failed notifications are a failed NeoFS network to me. also, i do know what such a handler should do. notify, panic but later, log?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Partial failure in many ways is better than complete failure, so handling exceptions makes some sense here, but I'd leave it to another issue.
raw := iterator.Value(it).([]byte)[1:] // 1 byte is an index | ||
if contract.Equals(raw) { | ||
return | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm a paranoiac about VM's EQUAL
and compiler, could we have a test for the contract that subscribes for notifications and after that subscribes one more time? In the end we should check that there's only one subscriber record stored in the netmap.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done
netmap/netmap_contract.go
Outdated
addrBalance interop.Hash160 // Balance contract not used legacy | ||
addrContainer interop.Hash160 // Container contract not used legacy |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
BTW, if these two fields are unused, then you can explicitly mark them as _
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
fixed
8b11124
8b11124
to
889c64c
Compare
889c64c
to
a52b3fe
Compare
Remove hardcoded "container" as a nice name TLD. It looks like a bug and has nothing useful. Also, fix tests that register "neofs" as a nice name TLD, that does not allow any contract test changes with the common TLD ("neofs") registration. Signed-off-by: Pavel Karpy <[email protected]>
Do not hardcode container and balance contract as a `NewEpoch` events receivers in the netmap contract. Use the new netmap's registration method on subscribers' deployment stages instead. Closes #327. Signed-off-by: Pavel Karpy <[email protected]>
Signed-off-by: Pavel Karpy <[email protected]>
Subscribe only contracts that can handle it with a corresponding method. Method's arg type is currently not possible to check but that is a Neo story not that repo's or the commit's one. Signed-off-by: Pavel Karpy <[email protected]>
a52b3fe
to
3fc8070
Compare
Signed-off-by: Pavel Karpy <[email protected]>
With `nolint` of course. Seems like `unused` ignores funcs that are marked with `nolint` and does not see the old keys usage. Signed-off-by: Pavel Karpy <[email protected]>
3fc8070
to
34f642f
Compare
Some var renamings, commit body fixes, sry. |
Do not hardcode container and balance contract as a
NewEpoch
events receivers in the netmap contract. Use the netmap's registration method on a deploy stage instead.