Skip to content

Commit

Permalink
core, services: fix Deignation-dependant service initialisation
Browse files Browse the repository at this point in the history
Initialise services dependant on roles designation based on N+1
block so that Genesis roles extension work properly. There's not
much sence to fetch node roles information for the latest persisted
block because Designation contract itself makes designated nodes
responsible since the next subsequent block.

A part of #3228.

Signed-off-by: Anna Shaleva <[email protected]>
  • Loading branch information
AnnaShaleva committed Nov 24, 2023
1 parent 4216efb commit 4d1e96e
Show file tree
Hide file tree
Showing 5 changed files with 76 additions and 2 deletions.
14 changes: 12 additions & 2 deletions pkg/core/blockchain.go
Original file line number Diff line number Diff line change
Expand Up @@ -332,6 +332,16 @@ func NewBlockchain(s storage.Store, cfg config.Blockchain, log *zap.Logger) (*Bl
return bc, nil
}

// GetDesignatedByRole returns a set of designated public keys for the given role
// relevant for the next block.
func (bc *Blockchain) GetDesignatedByRole(r noderoles.Role) (keys.PublicKeys, uint32, error) {
// Retrieve designated nodes starting from the next block, because the current
// block is already stored, thus, dependant services can't use PostPersist callback
// to fetch relevant information at their start.
res, h, err := bc.contracts.Designate.GetDesignatedByRole(bc.dao, r, bc.BlockHeight()+1)
return res, h, err
}

// SetOracle sets oracle module. It can safely be called on the running blockchain.
// To unregister Oracle service use SetOracle(nil).
func (bc *Blockchain) SetOracle(mod native.OracleService) {
Expand All @@ -343,7 +353,7 @@ func (bc *Blockchain) SetOracle(mod native.OracleService) {
}
mod.UpdateNativeContract(orc.NEF.Script, orc.GetOracleResponseScript(),
orc.Hash, md.MD.Offset)
keys, _, err := bc.contracts.Designate.GetDesignatedByRole(bc.dao, noderoles.Oracle, bc.BlockHeight())
keys, _, err := bc.GetDesignatedByRole(noderoles.Oracle)
if err != nil {
bc.log.Error("failed to get oracle key list")
return
Expand All @@ -364,7 +374,7 @@ func (bc *Blockchain) SetOracle(mod native.OracleService) {
// To unregister Notary service use SetNotary(nil).
func (bc *Blockchain) SetNotary(mod native.NotaryService) {
if mod != nil {
keys, _, err := bc.contracts.Designate.GetDesignatedByRole(bc.dao, noderoles.P2PNotary, bc.BlockHeight())
keys, _, err := bc.GetDesignatedByRole(noderoles.P2PNotary)
if err != nil {
bc.log.Error("failed to get notary key list")
return
Expand Down
25 changes: 25 additions & 0 deletions pkg/services/notary/core_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -747,3 +747,28 @@ func TestNotary(t *testing.T) {
}, 3*time.Second, 100*time.Millisecond)
checkFallbackTxs(t, requests, false)
}

func TestNotary_GenesisRoles(t *testing.T) {
const (
notaryPath = "./testdata/notary1.json"
notaryPass = "one"
)

w, err := wallet.NewWalletFromFile(notaryPath)
require.NoError(t, err)
require.NoError(t, w.Accounts[0].Decrypt(notaryPass, w.Scrypt))
acc := w.Accounts[0]

bc, _, _ := chain.NewMultiWithCustomConfig(t, func(c *config.Blockchain) {
c.P2PSigExtensions = true
c.Genesis.Roles = map[noderoles.Role]keys.PublicKeys{
noderoles.P2PNotary: {acc.PublicKey()},
}
})

_, ntr, _ := getTestNotary(t, bc, "./testdata/notary1.json", "one", func(tx *transaction.Transaction) error { return nil })
require.False(t, ntr.IsAuthorized())

bc.SetNotary(ntr)
require.True(t, ntr.IsAuthorized())
}
7 changes: 7 additions & 0 deletions pkg/services/notary/notary.go
Original file line number Diff line number Diff line change
Expand Up @@ -230,6 +230,13 @@ func (n *Notary) Shutdown() {
n.wallet.Close()
}

// IsAuthorized returns whether Notary service currently is authorized to collect
// signatures. It returnes true iff designated Notary node's account provided to
// the Notary service in decrypted state.
func (n *Notary) IsAuthorized() bool {
return n.getAccount() != nil
}

// OnNewRequest is a callback method which is called after a new notary request is added to the notary request pool.
func (n *Notary) OnNewRequest(payload *payload.P2PNotaryRequest) {
if !n.started.Load() {
Expand Down
7 changes: 7 additions & 0 deletions pkg/services/oracle/oracle.go
Original file line number Diff line number Diff line change
Expand Up @@ -206,6 +206,13 @@ func (o *Oracle) Start() {
go o.start()
}

// IsAuthorized returns whether Oracle service currently is authorized to collect
// signatures. It returns true iff designated Oracle node's account provided to
// the Oracle service in decrypted state.
func (o *Oracle) IsAuthorized() bool {
return o.getAccount() != nil
}

func (o *Oracle) start() {
o.requestMap <- o.pending // Guaranteed to not block, only AddRequests sends to it.
o.pending = nil
Expand Down
25 changes: 25 additions & 0 deletions pkg/services/oracle/oracle_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import (
"github.com/nspcc-dev/neo-go/pkg/core"
"github.com/nspcc-dev/neo-go/pkg/core/native"
"github.com/nspcc-dev/neo-go/pkg/core/native/nativenames"
"github.com/nspcc-dev/neo-go/pkg/core/native/noderoles"
"github.com/nspcc-dev/neo-go/pkg/core/state"
"github.com/nspcc-dev/neo-go/pkg/core/transaction"
"github.com/nspcc-dev/neo-go/pkg/crypto/keys"
Expand Down Expand Up @@ -339,6 +340,30 @@ func TestOracle(t *testing.T) {
})
}

func TestOracle_GenesisRole(t *testing.T) {
const (
oraclePath = "./testdata/oracle1.json"
oraclePass = "one"
)
w, err := wallet.NewWalletFromFile(oraclePath)
require.NoError(t, err)
require.NoError(t, w.Accounts[0].Decrypt(oraclePass, w.Scrypt))
acc := w.Accounts[0]

bc, _, _ := chain.NewMultiWithCustomConfig(t, func(c *config.Blockchain) {
c.Genesis.Roles = map[noderoles.Role]keys.PublicKeys{
noderoles.Oracle: {acc.PublicKey()},
}
})

orc, err := oracle.NewOracle(getOracleConfig(t, bc, "./testdata/oracle1.json", "one", nil))
require.NoError(t, err)
require.False(t, orc.IsAuthorized())

bc.SetOracle(orc)
require.True(t, orc.IsAuthorized())
}

func TestOracleFull(t *testing.T) {
bc, validator, committee := chain.NewMultiWithCustomConfigAndStore(t, nil, nil, false)
e := neotest.NewExecutor(t, bc, validator, committee)
Expand Down

0 comments on commit 4d1e96e

Please sign in to comment.