Merge pull request #1300 from nspcc-dev/various-preview3-fixes
Various preview3 testnet fixes
This commit is contained in:
commit
25ce154cf8
15 changed files with 89 additions and 100 deletions
|
@ -25,42 +25,6 @@ type storageOp struct {
|
|||
Value string `json:"value,omitempty"`
|
||||
}
|
||||
|
||||
// NEO has some differences of key storing (that should go away post-preview2).
|
||||
// ours format: contract's ID (uint32le) + key
|
||||
// theirs format: contract's ID (uint32le) + key with 16 between every 16 bytes, padded to len 16.
|
||||
func toNeoStorageKey(key []byte) []byte {
|
||||
if len(key) < 4 {
|
||||
panic("invalid key in storage")
|
||||
}
|
||||
|
||||
// Prefix is a contract's ID in LE.
|
||||
nkey := make([]byte, 4, len(key))
|
||||
copy(nkey, key[:4])
|
||||
key = key[4:]
|
||||
|
||||
index := 0
|
||||
remain := len(key)
|
||||
for remain >= 16 {
|
||||
nkey = append(nkey, key[index:index+16]...)
|
||||
nkey = append(nkey, 16)
|
||||
index += 16
|
||||
remain -= 16
|
||||
}
|
||||
|
||||
if remain > 0 {
|
||||
nkey = append(nkey, key[index:]...)
|
||||
}
|
||||
|
||||
padding := 16 - remain
|
||||
for i := 0; i < padding; i++ {
|
||||
nkey = append(nkey, 0)
|
||||
}
|
||||
|
||||
nkey = append(nkey, byte(remain))
|
||||
|
||||
return nkey
|
||||
}
|
||||
|
||||
// batchToMap converts batch to a map so that JSON is compatible
|
||||
// with https://github.com/NeoResearch/neo-storage-audit/
|
||||
func batchToMap(index uint32, batch *storage.MemBatch) blockDump {
|
||||
|
@ -77,10 +41,9 @@ func batchToMap(index uint32, batch *storage.MemBatch) blockDump {
|
|||
op = "Changed"
|
||||
}
|
||||
|
||||
key = toNeoStorageKey(key[1:])
|
||||
ops = append(ops, storageOp{
|
||||
State: op,
|
||||
Key: hex.EncodeToString(key),
|
||||
Key: hex.EncodeToString(key[1:]),
|
||||
Value: hex.EncodeToString(batch.Put[i].Value),
|
||||
})
|
||||
}
|
||||
|
@ -91,10 +54,9 @@ func batchToMap(index uint32, batch *storage.MemBatch) blockDump {
|
|||
continue
|
||||
}
|
||||
|
||||
key = toNeoStorageKey(key[1:])
|
||||
ops = append(ops, storageOp{
|
||||
State: "Deleted",
|
||||
Key: hex.EncodeToString(key),
|
||||
Key: hex.EncodeToString(key[1:]),
|
||||
})
|
||||
}
|
||||
|
||||
|
|
|
@ -518,7 +518,7 @@ func (s *service) newBlockFromContext(ctx *dbft.Context) block.Block {
|
|||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
script, err := smartcontract.CreateMultiSigRedeemScript(len(validators)-(len(validators)-1)/3, validators)
|
||||
script, err := smartcontract.CreateMultiSigRedeemScript(s.dbft.Context.M(), validators)
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
|
|
|
@ -226,7 +226,7 @@ func newTestService(t *testing.T) *service {
|
|||
}
|
||||
|
||||
func getTestValidator(i int) (*privateKey, *publicKey) {
|
||||
key := testchain.PrivateKeyByID(i)
|
||||
key := testchain.PrivateKey(i)
|
||||
return &privateKey{PrivateKey: key}, &publicKey{PublicKey: key.PublicKey()}
|
||||
}
|
||||
|
||||
|
|
|
@ -51,11 +51,7 @@ func (bc *Blockchain) newBlock(txs ...*transaction.Transaction) *block.Block {
|
|||
|
||||
func newBlock(cfg config.ProtocolConfiguration, index uint32, prev util.Uint256, txs ...*transaction.Transaction) *block.Block {
|
||||
validators, _ := validatorsFromConfig(cfg)
|
||||
vlen := len(validators)
|
||||
valScript, _ := smartcontract.CreateMultiSigRedeemScript(
|
||||
vlen-(vlen-1)/3,
|
||||
validators,
|
||||
)
|
||||
valScript, _ := smartcontract.CreateDefaultMultiSigRedeemScript(validators)
|
||||
witness := transaction.Witness{
|
||||
VerificationScript: valScript,
|
||||
}
|
||||
|
@ -393,7 +389,7 @@ func addSigners(txs ...*transaction.Transaction) {
|
|||
|
||||
func signTx(bc *Blockchain, txs ...*transaction.Transaction) error {
|
||||
validators := bc.GetStandByValidators()
|
||||
rawScript, err := smartcontract.CreateMultiSigRedeemScript(bc.config.ValidatorsCount/2+1, validators)
|
||||
rawScript, err := smartcontract.CreateDefaultMultiSigRedeemScript(validators)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to sign tx: %w", err)
|
||||
}
|
||||
|
|
|
@ -8,7 +8,6 @@ import (
|
|||
"github.com/nspcc-dev/neo-go/pkg/core/interop"
|
||||
"github.com/nspcc-dev/neo-go/pkg/core/state"
|
||||
"github.com/nspcc-dev/neo-go/pkg/crypto/hash"
|
||||
"github.com/nspcc-dev/neo-go/pkg/crypto/keys"
|
||||
"github.com/nspcc-dev/neo-go/pkg/smartcontract"
|
||||
"github.com/nspcc-dev/neo-go/pkg/util"
|
||||
)
|
||||
|
@ -73,7 +72,7 @@ func (g *GAS) Initialize(ic *interop.Context) error {
|
|||
if g.nep5TokenNative.getTotalSupply(ic.DAO).Sign() != 0 {
|
||||
return errors.New("already initialized")
|
||||
}
|
||||
h, _, err := getStandbyValidatorsHash(ic)
|
||||
h, err := getStandbyValidatorsHash(ic)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -103,13 +102,12 @@ func (g *GAS) OnPersist(ic *interop.Context) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
func getStandbyValidatorsHash(ic *interop.Context) (util.Uint160, []*keys.PublicKey, error) {
|
||||
vs := ic.Chain.GetStandByValidators()
|
||||
s, err := smartcontract.CreateMultiSigRedeemScript(len(vs)/2+1, vs)
|
||||
func getStandbyValidatorsHash(ic *interop.Context) (util.Uint160, error) {
|
||||
s, err := smartcontract.CreateDefaultMultiSigRedeemScript(ic.Chain.GetStandByValidators())
|
||||
if err != nil {
|
||||
return util.Uint160{}, nil, err
|
||||
return util.Uint160{}, err
|
||||
}
|
||||
return hash.Hash160(s), vs, nil
|
||||
return hash.Hash160(s), nil
|
||||
}
|
||||
|
||||
func chainOnPersist(fs ...func(*interop.Context) error) func(*interop.Context) error {
|
||||
|
|
|
@ -136,23 +136,17 @@ func (n *NEO) Initialize(ic *interop.Context) error {
|
|||
return errors.New("already initialized")
|
||||
}
|
||||
|
||||
h, vs, err := getStandbyValidatorsHash(ic)
|
||||
h, err := getStandbyValidatorsHash(ic)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
n.mint(ic, h, big.NewInt(NEOTotalSupply))
|
||||
|
||||
err = ic.DAO.PutStorageItem(n.ContractID, []byte{prefixVotersCount}, &state.StorageItem{Value: []byte{0}})
|
||||
err = ic.DAO.PutStorageItem(n.ContractID, []byte{prefixVotersCount}, &state.StorageItem{Value: []byte{}})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
for i := range vs {
|
||||
if err := n.RegisterCandidateInternal(ic, vs[i]); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
|
@ -422,6 +416,7 @@ func (n *NEO) GetValidatorsInternal(bc blockchainer.Blockchainer, d dao.DAO) (ke
|
|||
count = len(result)
|
||||
}
|
||||
result = result[:count]
|
||||
sort.Sort(result)
|
||||
n.validators.Store(result)
|
||||
return result, nil
|
||||
}
|
||||
|
|
|
@ -2,6 +2,7 @@ package core
|
|||
|
||||
import (
|
||||
"math/big"
|
||||
"sort"
|
||||
"testing"
|
||||
|
||||
"github.com/nspcc-dev/neo-go/pkg/config/netmode"
|
||||
|
@ -31,9 +32,11 @@ func TestNEO_Vote(t *testing.T) {
|
|||
ic := bc.newInteropContext(trigger.System, bc.dao, nil, tx)
|
||||
ic.VM = vm.New()
|
||||
|
||||
standBySorted := bc.GetStandByValidators()
|
||||
sort.Sort(standBySorted)
|
||||
pubs, err := neo.GetValidatorsInternal(bc, ic.DAO)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, bc.GetStandByValidators(), pubs)
|
||||
require.Equal(t, standBySorted, pubs)
|
||||
|
||||
sz := testchain.Size()
|
||||
|
||||
|
@ -62,21 +65,10 @@ func TestNEO_Vote(t *testing.T) {
|
|||
require.NoError(t, neo.VoteInternal(ic, h, candidates[i]))
|
||||
}
|
||||
|
||||
// First 3 validators must be the ones we have voted for.
|
||||
// We still haven't voted enough validators in.
|
||||
pubs, err = neo.GetValidatorsInternal(bc, ic.DAO)
|
||||
require.NoError(t, err)
|
||||
for i := 1; i < sz; i++ {
|
||||
require.Equal(t, pubs[i-1], candidates[i])
|
||||
}
|
||||
|
||||
var ok bool
|
||||
for _, p := range bc.GetStandByValidators() {
|
||||
if pubs[sz-1].Equal(p) {
|
||||
ok = true
|
||||
break
|
||||
}
|
||||
}
|
||||
require.True(t, ok, "last validator must be stand by")
|
||||
require.Equal(t, standBySorted, pubs)
|
||||
|
||||
// Register and give some value to the last validator.
|
||||
require.NoError(t, neo.RegisterCandidateInternal(ic, candidates[0]))
|
||||
|
@ -88,7 +80,9 @@ func TestNEO_Vote(t *testing.T) {
|
|||
|
||||
pubs, err = neo.GetValidatorsInternal(bc, ic.DAO)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, candidates, pubs)
|
||||
sortedCandidates := candidates.Copy()
|
||||
sort.Sort(sortedCandidates)
|
||||
require.EqualValues(t, sortedCandidates, pubs)
|
||||
|
||||
require.NoError(t, neo.UnregisterCandidateInternal(ic, candidates[0]))
|
||||
require.Error(t, neo.VoteInternal(ic, h, candidates[0]))
|
||||
|
|
|
@ -118,11 +118,7 @@ func committeeFromConfig(cfg config.ProtocolConfiguration) ([]*keys.PublicKey, e
|
|||
}
|
||||
|
||||
func getNextConsensusAddress(validators []*keys.PublicKey) (val util.Uint160, err error) {
|
||||
vlen := len(validators)
|
||||
raw, err := smartcontract.CreateMultiSigRedeemScript(
|
||||
vlen-(vlen-1)/3,
|
||||
validators,
|
||||
)
|
||||
raw, err := smartcontract.CreateDefaultMultiSigRedeemScript(validators)
|
||||
if err != nil {
|
||||
return val, err
|
||||
}
|
||||
|
|
|
@ -64,7 +64,7 @@ func MultisigVerificationScript() []byte {
|
|||
pubs = append(pubs, priv.PublicKey())
|
||||
}
|
||||
|
||||
script, err := smartcontract.CreateMultiSigRedeemScript(3, pubs)
|
||||
script, err := smartcontract.CreateDefaultMultiSigRedeemScript(pubs)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
|
|
@ -48,7 +48,7 @@ func (bq *blockQueue) run() {
|
|||
err := bq.chain.AddBlock(minblock)
|
||||
if err != nil {
|
||||
// The block might already be added by consensus.
|
||||
if _, errget := bq.chain.GetBlock(minblock.Hash()); errget != nil {
|
||||
if bq.chain.BlockHeight() < minblock.Index {
|
||||
bq.log.Warn("blockQueue: failed adding block into the blockchain",
|
||||
zap.String("error", err.Error()),
|
||||
zap.Uint32("blockHeight", bq.chain.BlockHeight()),
|
||||
|
|
|
@ -856,7 +856,7 @@ func (s *Server) getValidators(_ request.Params) (interface{}, *response.Error)
|
|||
if err != nil {
|
||||
return nil, response.NewRPCError("can't get enrollments", "", err)
|
||||
}
|
||||
var res []result.Validator
|
||||
var res = make([]result.Validator, 0)
|
||||
for _, v := range enrollments {
|
||||
res = append(res, result.Validator{
|
||||
PublicKey: *v.Key,
|
||||
|
|
|
@ -52,8 +52,8 @@ type rpcTestCase struct {
|
|||
check func(t *testing.T, e *executor, result interface{})
|
||||
}
|
||||
|
||||
const testContractHash = "36c3b0c85d98607db00b711885ec3e411d9b1672"
|
||||
const deploymentTxHash = "60a1fc8ceb7948d9933aec0cedd148441568575c40af7e0985cc366ed153d57e"
|
||||
const testContractHash = "5b5f77b947194ba45ff5fa1ba6e066af5636d110"
|
||||
const deploymentTxHash = "af0f94f6bdc5aada7abf1db19f1fcd2ea56cea596c41dc4abdfa6cd9664a7d72"
|
||||
|
||||
var rpcTestCases = map[string][]rpcTestCase{
|
||||
"getapplicationlog": {
|
||||
|
@ -451,6 +451,7 @@ var rpcTestCases = map[string][]rpcTestCase{
|
|||
result: func(*executor) interface{} {
|
||||
return &[]result.Validator{}
|
||||
},
|
||||
/* preview3 doesn't return any validators until there is a vote
|
||||
check: func(t *testing.T, e *executor, validators interface{}) {
|
||||
var expected []result.Validator
|
||||
sBValidators := e.chain.GetStandByValidators()
|
||||
|
@ -467,6 +468,7 @@ var rpcTestCases = map[string][]rpcTestCase{
|
|||
|
||||
assert.ElementsMatch(t, expected, *actual)
|
||||
},
|
||||
*/
|
||||
},
|
||||
},
|
||||
"getversion": {
|
||||
|
@ -1025,7 +1027,7 @@ func checkNep5Balances(t *testing.T, e *executor, acc interface{}) {
|
|||
},
|
||||
{
|
||||
Asset: e.chain.UtilityTokenHash(),
|
||||
Amount: "915.78962700",
|
||||
Amount: "915.61054740",
|
||||
LastUpdated: 6,
|
||||
}},
|
||||
Address: testchain.PrivateKeyByID(0).GetScriptHash().StringLE(),
|
||||
|
@ -1143,16 +1145,6 @@ func checkNep5TransfersAux(t *testing.T, e *executor, acc interface{}, start, en
|
|||
}
|
||||
netFee += b.Transactions[j].NetworkFee
|
||||
}
|
||||
if i > 0 {
|
||||
expected.Received = append(expected.Received, result.NEP5Transfer{
|
||||
Timestamp: b.Timestamp,
|
||||
Asset: e.chain.UtilityTokenHash(),
|
||||
Address: "", // minted from network fees.
|
||||
Amount: amountToString(big.NewInt(netFee), 8),
|
||||
Index: b.Index,
|
||||
TxHash: b.Hash(),
|
||||
})
|
||||
}
|
||||
}
|
||||
require.Equal(t, expected.Address, res.Address)
|
||||
|
||||
|
|
BIN
pkg/rpc/server/testdata/testblocks.acc
vendored
BIN
pkg/rpc/server/testdata/testblocks.acc
vendored
Binary file not shown.
|
@ -10,7 +10,8 @@ import (
|
|||
"github.com/nspcc-dev/neo-go/pkg/vm/opcode"
|
||||
)
|
||||
|
||||
// CreateMultiSigRedeemScript creates a script runnable by the VM.
|
||||
// CreateMultiSigRedeemScript creates an "m out of n" type verification script
|
||||
// where n is the length of publicKeys.
|
||||
func CreateMultiSigRedeemScript(m int, publicKeys keys.PublicKeys) ([]byte, error) {
|
||||
if m < 1 {
|
||||
return nil, fmt.Errorf("param m cannot be smaller or equal to 1 got %d", m)
|
||||
|
@ -34,3 +35,11 @@ func CreateMultiSigRedeemScript(m int, publicKeys keys.PublicKeys) ([]byte, erro
|
|||
|
||||
return buf.Bytes(), nil
|
||||
}
|
||||
|
||||
// CreateDefaultMultiSigRedeemScript creates an "m out of n" type verification script
|
||||
// using publicKeys length with the default BFT assumptions of (n - (n-1)/3) for m.
|
||||
func CreateDefaultMultiSigRedeemScript(publicKeys keys.PublicKeys) ([]byte, error) {
|
||||
n := len(publicKeys)
|
||||
m := n - (n-1)/3
|
||||
return CreateMultiSigRedeemScript(m, publicKeys)
|
||||
}
|
||||
|
|
|
@ -36,3 +36,50 @@ func TestCreateMultiSigRedeemScript(t *testing.T) {
|
|||
assert.Equal(t, opcode.SYSCALL, opcode.Opcode(br.ReadB()))
|
||||
assert.Equal(t, emit.InteropNameToID([]byte("Neo.Crypto.CheckMultisigWithECDsaSecp256r1")), br.ReadU32LE())
|
||||
}
|
||||
|
||||
func TestCreateDefaultMultiSigRedeemScript(t *testing.T) {
|
||||
var validators = make([]*keys.PublicKey, 0)
|
||||
|
||||
var addKey = func() {
|
||||
key, err := keys.NewPrivateKey()
|
||||
require.NoError(t, err)
|
||||
validators = append(validators, key.PublicKey())
|
||||
}
|
||||
var checkM = func(m int) {
|
||||
validScript, err := CreateMultiSigRedeemScript(m, validators)
|
||||
require.NoError(t, err)
|
||||
defaultScript, err := CreateDefaultMultiSigRedeemScript(validators)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, validScript, defaultScript)
|
||||
}
|
||||
|
||||
// 1 out of 1
|
||||
addKey()
|
||||
checkM(1)
|
||||
|
||||
// 2 out of 2
|
||||
addKey()
|
||||
checkM(2)
|
||||
|
||||
// 3 out of 4
|
||||
for i := 0; i < 2; i++ {
|
||||
addKey()
|
||||
}
|
||||
checkM(3)
|
||||
|
||||
// 5 out of 6
|
||||
for i := 0; i < 2; i++ {
|
||||
addKey()
|
||||
}
|
||||
checkM(5)
|
||||
|
||||
// 5 out of 7
|
||||
addKey()
|
||||
checkM(5)
|
||||
|
||||
// 7 out of 10
|
||||
for i := 0; i < 3; i++ {
|
||||
addKey()
|
||||
}
|
||||
checkM(7)
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue