forked from TrueCloudLab/neoneo-go
*: add GenesisTransaction extension to the protocol configuration
Provide a script that should be deployed in the genesis block. Signed-off-by: Anna Shaleva <shaleva.ann@nspcc.ru>
This commit is contained in:
parent
065bd3f0be
commit
8cc32a91b6
8 changed files with 178 additions and 13 deletions
|
@ -365,6 +365,9 @@ Genesis:
|
||||||
Oracle:
|
Oracle:
|
||||||
- 03409f31f0d66bdc2f70a9730b66fe186658f84a8018204db01c106edc36553cd0
|
- 03409f31f0d66bdc2f70a9730b66fe186658f84a8018204db01c106edc36553cd0
|
||||||
- 0222038884bbd1d8ff109ed3bdef3542e768eef76c1247aea8bc8171f532928c30
|
- 0222038884bbd1d8ff109ed3bdef3542e768eef76c1247aea8bc8171f532928c30
|
||||||
|
Transaction:
|
||||||
|
Script: "DCECEDp/fdAWVYWX95YNJ8UWpDlP2Wi55lFV60sBPkBAQG5BVuezJw=="
|
||||||
|
SystemFee: 100000000
|
||||||
```
|
```
|
||||||
where:
|
where:
|
||||||
- `Roles` is a map from node roles that should be set at the moment of native
|
- `Roles` is a map from node roles that should be set at the moment of native
|
||||||
|
@ -383,3 +386,15 @@ where:
|
||||||
with NativeUpdateHistory setting, which means that specified roles will be set
|
with NativeUpdateHistory setting, which means that specified roles will be set
|
||||||
only during native RoleManagement contract initialisation (which may be
|
only during native RoleManagement contract initialisation (which may be
|
||||||
performed in some non-genesis block). By default, no roles are designated.
|
performed in some non-genesis block). By default, no roles are designated.
|
||||||
|
|
||||||
|
- `Transaction` is a container for transaction script that should be deployed in
|
||||||
|
the genesis block if provided. `Transaction` includes `Script` which is a
|
||||||
|
base64-encoded transaction script and `SystemFee` which is a transaction's
|
||||||
|
system fee value (in GAS) that will be spent during transaction execution.
|
||||||
|
Transaction generated from the provided parameters has two signers at max with
|
||||||
|
CalledByEntry witness scope: the first one is standby validators multisignature
|
||||||
|
signer and the second one (if differs from the first) is committee
|
||||||
|
multisignature signer.
|
||||||
|
|
||||||
|
Note that `Transaction` is a NeoGo extension that isn't supported by the NeoC#
|
||||||
|
node and must be disabled on the public Neo N3 networks.
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
package config
|
package config
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"encoding/base64"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
"github.com/nspcc-dev/neo-go/pkg/core/native/noderoles"
|
"github.com/nspcc-dev/neo-go/pkg/core/native/noderoles"
|
||||||
|
@ -14,13 +15,35 @@ type Genesis struct {
|
||||||
// Designation contract initialization. It is NeoGo extension and must be
|
// Designation contract initialization. It is NeoGo extension and must be
|
||||||
// disabled on the public Neo N3 networks.
|
// disabled on the public Neo N3 networks.
|
||||||
Roles map[noderoles.Role]keys.PublicKeys
|
Roles map[noderoles.Role]keys.PublicKeys
|
||||||
|
// Transaction contains transaction script that should be deployed in the
|
||||||
|
// genesis block. It is NeoGo extension and must be disabled on the public
|
||||||
|
// Neo N3 networks.
|
||||||
|
Transaction *GenesisTransaction
|
||||||
}
|
}
|
||||||
|
|
||||||
// genesisAux is an auxiliary structure for Genesis YAML marshalling.
|
// GenesisTransaction is a placeholder for script that should be included into genesis
|
||||||
type genesisAux struct {
|
// block as a transaction script with the given system fee. Provided
|
||||||
Roles map[string]keys.PublicKeys `yaml:"Roles"`
|
// system fee value will be taken from the standby validators account which is
|
||||||
|
// added to the list of Signers as a sender with CalledByEntry scope.
|
||||||
|
type GenesisTransaction struct {
|
||||||
|
Script []byte
|
||||||
|
SystemFee int64
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type (
|
||||||
|
// genesisAux is an auxiliary structure for Genesis YAML marshalling.
|
||||||
|
genesisAux struct {
|
||||||
|
Roles map[string]keys.PublicKeys `yaml:"Roles"`
|
||||||
|
Transaction *genesisTransactionAux `yaml:"Transaction"`
|
||||||
|
}
|
||||||
|
// genesisTransactionAux is an auxiliary structure for GenesisTransaction YAML
|
||||||
|
// marshalling.
|
||||||
|
genesisTransactionAux struct {
|
||||||
|
Script string `yaml:"Script"`
|
||||||
|
SystemFee int64 `yaml:"SystemFee"`
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
// MarshalYAML implements the YAML marshaler interface.
|
// MarshalYAML implements the YAML marshaler interface.
|
||||||
func (e Genesis) MarshalYAML() (any, error) {
|
func (e Genesis) MarshalYAML() (any, error) {
|
||||||
var aux genesisAux
|
var aux genesisAux
|
||||||
|
@ -28,6 +51,12 @@ func (e Genesis) MarshalYAML() (any, error) {
|
||||||
for r, ks := range e.Roles {
|
for r, ks := range e.Roles {
|
||||||
aux.Roles[r.String()] = ks
|
aux.Roles[r.String()] = ks
|
||||||
}
|
}
|
||||||
|
if e.Transaction != nil {
|
||||||
|
aux.Transaction = &genesisTransactionAux{
|
||||||
|
Script: base64.StdEncoding.EncodeToString(e.Transaction.Script),
|
||||||
|
SystemFee: e.Transaction.SystemFee,
|
||||||
|
}
|
||||||
|
}
|
||||||
return aux, nil
|
return aux, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -47,5 +76,16 @@ func (e *Genesis) UnmarshalYAML(unmarshal func(any) error) error {
|
||||||
e.Roles[r] = ks
|
e.Roles[r] = ks
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if aux.Transaction != nil {
|
||||||
|
script, err := base64.StdEncoding.DecodeString(aux.Transaction.Script)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("failed to decode script of genesis transaction: %w", err)
|
||||||
|
}
|
||||||
|
e.Transaction = &GenesisTransaction{
|
||||||
|
Script: script,
|
||||||
|
SystemFee: aux.Transaction.SystemFee,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
package config
|
package config
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"encoding/base64"
|
||||||
"encoding/hex"
|
"encoding/hex"
|
||||||
"fmt"
|
"fmt"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
|
@ -293,6 +294,10 @@ func TestGenesisExtensionsMarshalYAML(t *testing.T) {
|
||||||
noderoles.NeoFSAlphabet: {pub},
|
noderoles.NeoFSAlphabet: {pub},
|
||||||
noderoles.P2PNotary: {pub},
|
noderoles.P2PNotary: {pub},
|
||||||
},
|
},
|
||||||
|
Transaction: &GenesisTransaction{
|
||||||
|
Script: []byte{1, 2, 3, 4},
|
||||||
|
SystemFee: 123,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
testserdes.MarshalUnmarshalYAML(t, g, new(Genesis))
|
testserdes.MarshalUnmarshalYAML(t, g, new(Genesis))
|
||||||
})
|
})
|
||||||
|
@ -300,20 +305,36 @@ func TestGenesisExtensionsMarshalYAML(t *testing.T) {
|
||||||
t.Run("unmarshal config", func(t *testing.T) {
|
t.Run("unmarshal config", func(t *testing.T) {
|
||||||
t.Run("good", func(t *testing.T) {
|
t.Run("good", func(t *testing.T) {
|
||||||
pubStr := hex.EncodeToString(pub.Bytes())
|
pubStr := hex.EncodeToString(pub.Bytes())
|
||||||
|
script := []byte{1, 2, 3, 4}
|
||||||
cfgYml := fmt.Sprintf(`ProtocolConfiguration:
|
cfgYml := fmt.Sprintf(`ProtocolConfiguration:
|
||||||
Genesis:
|
Genesis:
|
||||||
|
Transaction:
|
||||||
|
Script: "%s"
|
||||||
|
SystemFee: 123
|
||||||
Roles:
|
Roles:
|
||||||
NeoFSAlphabet:
|
NeoFSAlphabet:
|
||||||
- %s
|
- %s
|
||||||
- %s
|
- %s
|
||||||
Oracle:
|
Oracle:
|
||||||
- %s
|
- %s
|
||||||
- %s`, pubStr, pubStr, pubStr, pubStr)
|
- %s`, base64.StdEncoding.EncodeToString(script), pubStr, pubStr, pubStr, pubStr)
|
||||||
cfg := new(Config)
|
cfg := new(Config)
|
||||||
require.NoError(t, yaml.Unmarshal([]byte(cfgYml), cfg))
|
require.NoError(t, yaml.Unmarshal([]byte(cfgYml), cfg))
|
||||||
require.Equal(t, 2, len(cfg.ProtocolConfiguration.Genesis.Roles))
|
require.Equal(t, 2, len(cfg.ProtocolConfiguration.Genesis.Roles))
|
||||||
require.Equal(t, keys.PublicKeys{pub, pub}, cfg.ProtocolConfiguration.Genesis.Roles[noderoles.NeoFSAlphabet])
|
require.Equal(t, keys.PublicKeys{pub, pub}, cfg.ProtocolConfiguration.Genesis.Roles[noderoles.NeoFSAlphabet])
|
||||||
require.Equal(t, keys.PublicKeys{pub, pub}, cfg.ProtocolConfiguration.Genesis.Roles[noderoles.Oracle])
|
require.Equal(t, keys.PublicKeys{pub, pub}, cfg.ProtocolConfiguration.Genesis.Roles[noderoles.Oracle])
|
||||||
|
require.Equal(t, &GenesisTransaction{
|
||||||
|
Script: script,
|
||||||
|
SystemFee: 123,
|
||||||
|
}, cfg.ProtocolConfiguration.Genesis.Transaction)
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("empty", func(t *testing.T) {
|
||||||
|
cfgYml := `ProtocolConfiguration:`
|
||||||
|
cfg := new(Config)
|
||||||
|
require.NoError(t, yaml.Unmarshal([]byte(cfgYml), cfg))
|
||||||
|
require.Nil(t, cfg.ProtocolConfiguration.Genesis.Transaction)
|
||||||
|
require.Empty(t, cfg.ProtocolConfiguration.Genesis.Roles)
|
||||||
})
|
})
|
||||||
|
|
||||||
t.Run("unknown role", func(t *testing.T) {
|
t.Run("unknown role", func(t *testing.T) {
|
||||||
|
|
|
@ -47,7 +47,9 @@ import (
|
||||||
const (
|
const (
|
||||||
version = "0.2.10"
|
version = "0.2.10"
|
||||||
|
|
||||||
defaultInitialGAS = 52000000_00000000
|
// DefaultInitialGAS is the default amount of GAS emitted to the standby validators
|
||||||
|
// multisignature account during native GAS contract initialization.
|
||||||
|
DefaultInitialGAS = 52000000_00000000
|
||||||
defaultGCPeriod = 10000
|
defaultGCPeriod = 10000
|
||||||
defaultMemPoolSize = 50000
|
defaultMemPoolSize = 50000
|
||||||
defaultP2PNotaryRequestPayloadPoolSize = 1000
|
defaultP2PNotaryRequestPayloadPoolSize = 1000
|
||||||
|
@ -228,7 +230,7 @@ func NewBlockchain(s storage.Store, cfg config.Blockchain, log *zap.Logger) (*Bl
|
||||||
|
|
||||||
// Protocol configuration fixups/checks.
|
// Protocol configuration fixups/checks.
|
||||||
if cfg.InitialGASSupply <= 0 {
|
if cfg.InitialGASSupply <= 0 {
|
||||||
cfg.InitialGASSupply = fixedn.Fixed8(defaultInitialGAS)
|
cfg.InitialGASSupply = fixedn.Fixed8(DefaultInitialGAS)
|
||||||
log.Info("initial gas supply is not set or wrong, setting default value", zap.Stringer("InitialGASSupply", cfg.InitialGASSupply))
|
log.Info("initial gas supply is not set or wrong, setting default value", zap.Stringer("InitialGASSupply", cfg.InitialGASSupply))
|
||||||
}
|
}
|
||||||
if cfg.MemPoolSize <= 0 {
|
if cfg.MemPoolSize <= 0 {
|
||||||
|
|
|
@ -13,6 +13,7 @@ import (
|
||||||
"github.com/nspcc-dev/neo-go/internal/basicchain"
|
"github.com/nspcc-dev/neo-go/internal/basicchain"
|
||||||
"github.com/nspcc-dev/neo-go/internal/contracts"
|
"github.com/nspcc-dev/neo-go/internal/contracts"
|
||||||
"github.com/nspcc-dev/neo-go/internal/random"
|
"github.com/nspcc-dev/neo-go/internal/random"
|
||||||
|
"github.com/nspcc-dev/neo-go/internal/testchain"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/compiler"
|
"github.com/nspcc-dev/neo-go/pkg/compiler"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/config"
|
"github.com/nspcc-dev/neo-go/pkg/config"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/config/netmode"
|
"github.com/nspcc-dev/neo-go/pkg/config/netmode"
|
||||||
|
@ -37,6 +38,7 @@ import (
|
||||||
"github.com/nspcc-dev/neo-go/pkg/neotest"
|
"github.com/nspcc-dev/neo-go/pkg/neotest"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/neotest/chain"
|
"github.com/nspcc-dev/neo-go/pkg/neotest/chain"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/smartcontract"
|
"github.com/nspcc-dev/neo-go/pkg/smartcontract"
|
||||||
|
"github.com/nspcc-dev/neo-go/pkg/smartcontract/callflag"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/smartcontract/trigger"
|
"github.com/nspcc-dev/neo-go/pkg/smartcontract/trigger"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/util"
|
"github.com/nspcc-dev/neo-go/pkg/util"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/vm/emit"
|
"github.com/nspcc-dev/neo-go/pkg/vm/emit"
|
||||||
|
@ -2438,3 +2440,36 @@ func TestBlockchain_ResetState(t *testing.T) {
|
||||||
}
|
}
|
||||||
require.Equal(t, expectedLUB, lub)
|
require.Equal(t, expectedLUB, lub)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestBlockchain_GenesisTransactionExtension(t *testing.T) {
|
||||||
|
priv0 := testchain.PrivateKeyByID(0)
|
||||||
|
acc0 := wallet.NewAccountFromPrivateKey(priv0)
|
||||||
|
require.NoError(t, acc0.ConvertMultisig(1, []*keys.PublicKey{priv0.PublicKey()}))
|
||||||
|
from := acc0.ScriptHash()
|
||||||
|
to := util.Uint160{1, 2, 3}
|
||||||
|
amount := 1
|
||||||
|
|
||||||
|
script := io.NewBufBinWriter()
|
||||||
|
emit.Bytes(script.BinWriter, from.BytesBE())
|
||||||
|
emit.Syscall(script.BinWriter, interopnames.SystemRuntimeCheckWitness)
|
||||||
|
emit.Bytes(script.BinWriter, to.BytesBE())
|
||||||
|
emit.Syscall(script.BinWriter, interopnames.SystemRuntimeCheckWitness)
|
||||||
|
emit.AppCall(script.BinWriter, state.CreateNativeContractHash(nativenames.Neo), "transfer", callflag.All, from, to, amount, nil)
|
||||||
|
emit.Opcodes(script.BinWriter, opcode.ASSERT)
|
||||||
|
|
||||||
|
var sysFee int64 = 1_0000_0000
|
||||||
|
bc, acc := chain.NewSingleWithCustomConfig(t, func(blockchain *config.Blockchain) {
|
||||||
|
blockchain.Genesis.Transaction = &config.GenesisTransaction{
|
||||||
|
Script: script.Bytes(),
|
||||||
|
SystemFee: sysFee,
|
||||||
|
}
|
||||||
|
})
|
||||||
|
e := neotest.NewExecutor(t, bc, acc, acc)
|
||||||
|
b := e.GetBlockByIndex(t, 0)
|
||||||
|
tx := b.Transactions[0]
|
||||||
|
e.CheckHalt(t, tx.Hash(), stackitem.NewBool(true), stackitem.NewBool(false))
|
||||||
|
e.CheckGASBalance(t, e.Validator.ScriptHash(), big.NewInt(core.DefaultInitialGAS-sysFee))
|
||||||
|
actualNeo, lub := e.Chain.GetGoverningTokenBalance(to)
|
||||||
|
require.Equal(t, int64(amount), actualNeo.Int64())
|
||||||
|
require.Equal(t, 0, int(lub))
|
||||||
|
}
|
||||||
|
|
|
@ -80,7 +80,7 @@ func newBlock(cfg config.ProtocolConfiguration, index uint32, prev util.Uint256,
|
||||||
|
|
||||||
func newBlockCustom(cfg config.ProtocolConfiguration, f func(b *block.Block),
|
func newBlockCustom(cfg config.ProtocolConfiguration, f func(b *block.Block),
|
||||||
txs ...*transaction.Transaction) *block.Block {
|
txs ...*transaction.Transaction) *block.Block {
|
||||||
validators, _ := validatorsFromConfig(cfg)
|
validators, _, _ := validatorsFromConfig(cfg)
|
||||||
valScript, _ := smartcontract.CreateDefaultMultiSigRedeemScript(validators)
|
valScript, _ := smartcontract.CreateDefaultMultiSigRedeemScript(validators)
|
||||||
witness := transaction.Witness{
|
witness := transaction.Witness{
|
||||||
VerificationScript: valScript,
|
VerificationScript: valScript,
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
package core
|
package core
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"fmt"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/nspcc-dev/neo-go/pkg/config"
|
"github.com/nspcc-dev/neo-go/pkg/config"
|
||||||
|
@ -15,7 +16,7 @@ import (
|
||||||
|
|
||||||
// CreateGenesisBlock creates a genesis block based on the given configuration.
|
// CreateGenesisBlock creates a genesis block based on the given configuration.
|
||||||
func CreateGenesisBlock(cfg config.ProtocolConfiguration) (*block.Block, error) {
|
func CreateGenesisBlock(cfg config.ProtocolConfiguration) (*block.Block, error) {
|
||||||
validators, err := validatorsFromConfig(cfg)
|
validators, committee, err := validatorsFromConfig(cfg)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
@ -25,6 +26,49 @@ func CreateGenesisBlock(cfg config.ProtocolConfiguration) (*block.Block, error)
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
txs := []*transaction.Transaction{}
|
||||||
|
if cfg.Genesis.Transaction != nil {
|
||||||
|
committeeH, err := getCommitteeAddress(committee)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("failed to calculate committee address: %w", err)
|
||||||
|
}
|
||||||
|
tx := cfg.Genesis.Transaction
|
||||||
|
signers := []transaction.Signer{
|
||||||
|
{
|
||||||
|
Account: nextConsensus,
|
||||||
|
Scopes: transaction.CalledByEntry,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
scripts := []transaction.Witness{
|
||||||
|
{
|
||||||
|
InvocationScript: []byte{},
|
||||||
|
VerificationScript: []byte{byte(opcode.PUSH1)},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
if !committeeH.Equals(nextConsensus) {
|
||||||
|
signers = append(signers, []transaction.Signer{
|
||||||
|
{
|
||||||
|
Account: committeeH,
|
||||||
|
Scopes: transaction.CalledByEntry,
|
||||||
|
},
|
||||||
|
}...)
|
||||||
|
scripts = append(scripts, []transaction.Witness{
|
||||||
|
{
|
||||||
|
InvocationScript: []byte{},
|
||||||
|
VerificationScript: []byte{byte(opcode.PUSH1)},
|
||||||
|
},
|
||||||
|
}...)
|
||||||
|
}
|
||||||
|
|
||||||
|
txs = append(txs, &transaction.Transaction{
|
||||||
|
SystemFee: tx.SystemFee,
|
||||||
|
ValidUntilBlock: 1,
|
||||||
|
Script: tx.Script,
|
||||||
|
Signers: signers,
|
||||||
|
Scripts: scripts,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
base := block.Header{
|
base := block.Header{
|
||||||
Version: 0,
|
Version: 0,
|
||||||
PrevHash: util.Uint256{},
|
PrevHash: util.Uint256{},
|
||||||
|
@ -41,19 +85,19 @@ func CreateGenesisBlock(cfg config.ProtocolConfiguration) (*block.Block, error)
|
||||||
|
|
||||||
b := &block.Block{
|
b := &block.Block{
|
||||||
Header: base,
|
Header: base,
|
||||||
Transactions: []*transaction.Transaction{},
|
Transactions: txs,
|
||||||
}
|
}
|
||||||
b.RebuildMerkleRoot()
|
b.RebuildMerkleRoot()
|
||||||
|
|
||||||
return b, nil
|
return b, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func validatorsFromConfig(cfg config.ProtocolConfiguration) ([]*keys.PublicKey, error) {
|
func validatorsFromConfig(cfg config.ProtocolConfiguration) ([]*keys.PublicKey, []*keys.PublicKey, error) {
|
||||||
vs, err := keys.NewPublicKeysFromStrings(cfg.StandbyCommittee)
|
vs, err := keys.NewPublicKeysFromStrings(cfg.StandbyCommittee)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, nil, err
|
||||||
}
|
}
|
||||||
return vs[:cfg.GetNumOfCNs(0)], nil
|
return vs.Copy()[:cfg.GetNumOfCNs(0)], vs, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func getNextConsensusAddress(validators []*keys.PublicKey) (val util.Uint160, err error) {
|
func getNextConsensusAddress(validators []*keys.PublicKey) (val util.Uint160, err error) {
|
||||||
|
@ -64,6 +108,14 @@ func getNextConsensusAddress(validators []*keys.PublicKey) (val util.Uint160, er
|
||||||
return hash.Hash160(raw), nil
|
return hash.Hash160(raw), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func getCommitteeAddress(committee []*keys.PublicKey) (val util.Uint160, err error) {
|
||||||
|
raw, err := smartcontract.CreateMajorityMultiSigRedeemScript(committee)
|
||||||
|
if err != nil {
|
||||||
|
return val, err
|
||||||
|
}
|
||||||
|
return hash.Hash160(raw), nil
|
||||||
|
}
|
||||||
|
|
||||||
// hashSliceReverse reverses the given slice of util.Uint256.
|
// hashSliceReverse reverses the given slice of util.Uint256.
|
||||||
func hashSliceReverse(dest []util.Uint256) {
|
func hashSliceReverse(dest []util.Uint256) {
|
||||||
for i, j := 0, len(dest)-1; i < j; i, j = i+1, j-1 {
|
for i, j := 0, len(dest)-1; i < j; i, j = i+1, j-1 {
|
||||||
|
|
|
@ -30,7 +30,7 @@ func TestGetConsensusAddressMainNet(t *testing.T) {
|
||||||
cfg, err := config.Load("../../config", netmode.MainNet)
|
cfg, err := config.Load("../../config", netmode.MainNet)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
validators, err := validatorsFromConfig(cfg.ProtocolConfiguration)
|
validators, _, err := validatorsFromConfig(cfg.ProtocolConfiguration)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
script, err := getNextConsensusAddress(validators)
|
script, err := getNextConsensusAddress(validators)
|
||||||
|
|
Loading…
Reference in a new issue