Skip to content

Commit

Permalink
netmap: Make NewEpoch callback mechanism more generic
Browse files Browse the repository at this point in the history
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. Closes #327.

Signed-off-by: Pavel Karpy <[email protected]>
  • Loading branch information
carpawell committed Nov 20, 2023
1 parent 73882ca commit dc252aa
Show file tree
Hide file tree
Showing 8 changed files with 162 additions and 8 deletions.
2 changes: 2 additions & 0 deletions balance/balance_contract.go
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,8 @@ func _deploy(data any, isUpdate bool) {
switchToNotary(ctx)
}

common.RegisterNewEpochHook()

return
}

Expand Down
2 changes: 1 addition & 1 deletion balance/config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ name: "NeoFS Balance"
supportedstandards: ["NEP-17"]
safemethods: ["balanceOf", "decimals", "symbol", "totalSupply", "version"]
permissions:
- methods: ["update"]
- methods: ["update", "registerNewEpochRecipient"]
events:
- name: Lock
parameters:
Expand Down
39 changes: 39 additions & 0 deletions common/netmap.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
package common

import (
"github.com/nspcc-dev/neo-go/pkg/interop"
"github.com/nspcc-dev/neo-go/pkg/interop/contract"
"github.com/nspcc-dev/neo-go/pkg/interop/convert"
"github.com/nspcc-dev/neo-go/pkg/interop/lib/address"
"github.com/nspcc-dev/neo-go/pkg/interop/native/management"
"github.com/nspcc-dev/neo-go/pkg/interop/native/std"
"github.com/nspcc-dev/neo-go/pkg/interop/runtime"
)

// RegisterNewEpochHook registers calling contract as a NewEpoch
// callback requester. Netmap contract's address is taken from the
// NNS contract, therefore, it must be presented and filled with
// netmap information for correct RegisterNewEpochHook call; otherwise
// successive call is not guaranteed.
// Caller must have `NewEpoch` method with a single numeric argument.
func RegisterNewEpochHook() {
nnsContract := management.GetContractByID(1)
if nnsContract == nil {
panic("missing NNS contract")
}

resolveRes := contract.Call(nnsContract.Hash, "resolve", contract.ReadOnly, "netmap.neofs", 16)
records := resolveRes.([]string)
if len(records) == 0 {
panic("did not find a record of the Proxy contract in the NNS")
}

var netmapContract interop.Hash160
if len(records[0]) == 2*interop.Hash160Len {
netmapContract = convert.ToBytes(std.Atoi(records[0], 16))
} else {
netmapContract = address.ToHash160(records[0])
}

contract.Call(netmapContract, "registerNewEpochRecipient", contract.All, runtime.GetExecutingScriptHash())
}
2 changes: 1 addition & 1 deletion container/config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ name: "NeoFS Container"
safemethods: ["alias", "count", "containersOf", "get", "owner", "list", "eACL", "getContainerSize", "listContainerSizes", "iterateContainerSizes", "iterateAllContainerSizes", "version"]
permissions:
- methods: ["update", "addKey", "transferX",
"register", "registerTLD", "addRecord", "deleteRecords"]
"register", "registerTLD", "addRecord", "deleteRecords", "registerNewEpochRecipient"]
events:
- name: PutSuccess
parameters:
Expand Down
2 changes: 2 additions & 0 deletions container/container_contract.go
Original file line number Diff line number Diff line change
Expand Up @@ -138,6 +138,8 @@ func _deploy(data any, isUpdate bool) {
switchToNotary(ctx)
}

common.RegisterNewEpochHook()

return
}

Expand Down
4 changes: 4 additions & 0 deletions netmap/config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -17,3 +17,7 @@ events:
parameters:
- name: epoch
type: Integer
- name: NewEpochHookRegistration
parameters:
- name: registree
type: Hash160
30 changes: 24 additions & 6 deletions netmap/netmap_contract.go
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,8 @@ const (
containerContractKey = "containerScriptHash"

Check failure on line 73 in netmap/netmap_contract.go

View workflow job for this annotation

GitHub Actions / Lint

const `containerContractKey` is unused (unused)
balanceContractKey = "balanceScriptHash"

Check failure on line 74 in netmap/netmap_contract.go

View workflow job for this annotation

GitHub Actions / Lint

const `balanceContractKey` is unused (unused)

cleanupEpochMethod = "newEpoch"
newEpochRecipientsKey = "newEpochRecipients"
cleanupEpochMethod = "newEpoch"

// nodeKeyOffset is an offset in a serialized node info representation (V2 format)
// marking the start of the node's public key.
Expand Down Expand Up @@ -601,6 +602,23 @@ func ListConfig() []record {
return config
}

// RegisterNewEpochRecipient registers passed contract as a NewEpoch event
// receiver. Such a contract must have a `NewEpoch` method with a single numeric
// argument. Transactions that call RegisterNewEpochRecipient must be witnessed
// by the Alphabet.
// Produces `NewEpochHookRegistration` notification event with a just registered
// recipient in a success case.
func RegisterNewEpochRecipient(contract interop.Hash160) {
common.CheckAlphabetWitness(common.AlphabetAddress())

ctx := storage.GetContext()
key := append([]byte(newEpochRecipientsKey), contract...)

storage.Put(ctx, key, 1)

runtime.Notify("NewEpochHookRegistration", contract)
}

// Version returns the version of the contract.
func Version() int {
return common.Version
Expand Down Expand Up @@ -685,9 +703,9 @@ func setConfig(ctx storage.Context, key, val any) {
}

func cleanup(ctx storage.Context, epoch int) {
balanceContractAddr := storage.Get(ctx, balanceContractKey).(interop.Hash160)
contract.Call(balanceContractAddr, cleanupEpochMethod, contract.All, epoch)

containerContractAddr := storage.Get(ctx, containerContractKey).(interop.Hash160)
contract.Call(containerContractAddr, cleanupEpochMethod, contract.All, epoch)
it := storage.Find(ctx, newEpochRecipientsKey, storage.RemovePrefix|storage.KeysOnly)
for iterator.Next(it) {
contractHash := iterator.Value(it).(interop.Hash160)
contract.Call(contractHash, cleanupEpochMethod, contract.All, epoch)
}
}
89 changes: 89 additions & 0 deletions rpc/netmap/rpcbinding.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

0 comments on commit dc252aa

Please sign in to comment.