1df447cd68
Extendable validators
187 lines
5.6 KiB
Go
187 lines
5.6 KiB
Go
package main
|
|
|
|
import (
|
|
"crypto/rand"
|
|
"errors"
|
|
"flag"
|
|
"fmt"
|
|
"os"
|
|
"strings"
|
|
"time"
|
|
|
|
"github.com/nspcc-dev/neo-go/internal/testchain"
|
|
"github.com/nspcc-dev/neo-go/pkg/config"
|
|
"github.com/nspcc-dev/neo-go/pkg/config/netmode"
|
|
"github.com/nspcc-dev/neo-go/pkg/core"
|
|
"github.com/nspcc-dev/neo-go/pkg/core/block"
|
|
"github.com/nspcc-dev/neo-go/pkg/core/chaindump"
|
|
"github.com/nspcc-dev/neo-go/pkg/core/native"
|
|
"github.com/nspcc-dev/neo-go/pkg/core/storage"
|
|
"github.com/nspcc-dev/neo-go/pkg/core/transaction"
|
|
"github.com/nspcc-dev/neo-go/pkg/io"
|
|
"github.com/nspcc-dev/neo-go/pkg/smartcontract"
|
|
"github.com/nspcc-dev/neo-go/pkg/smartcontract/callflag"
|
|
"github.com/nspcc-dev/neo-go/pkg/vm/emit"
|
|
"github.com/nspcc-dev/neo-go/pkg/wallet"
|
|
"go.uber.org/zap"
|
|
"go.uber.org/zap/zapcore"
|
|
)
|
|
|
|
// Takes 1 minute for 100 tx per block and 5000 blocks.
|
|
const (
|
|
defaultBlockCount = 5000
|
|
defaultTxPerBlock = 100
|
|
)
|
|
|
|
var (
|
|
outFile = flag.String("out", "", "filename to write dump to")
|
|
blockCount = flag.Uint("blocks", defaultBlockCount, "number of blocks to generate")
|
|
txPerBlock = flag.Uint("txs", defaultTxPerBlock, "number of blocks to generate")
|
|
)
|
|
|
|
func main() {
|
|
flag.Parse()
|
|
|
|
if *outFile == "" {
|
|
handleError("", errors.New("output file is not provided"))
|
|
}
|
|
outStream, err := os.Create(*outFile) // fail early
|
|
handleError("can't open output file", err)
|
|
defer outStream.Close()
|
|
|
|
const contract = `
|
|
package contract
|
|
import "github.com/nspcc-dev/neo-go/pkg/interop/storage"
|
|
var ctx = storage.GetContext()
|
|
func Put(key, value []byte) {
|
|
storage.Put(ctx, key, value)
|
|
}`
|
|
|
|
acc, err := wallet.NewAccount()
|
|
handleError("can't create new account", err)
|
|
h := acc.Contract.ScriptHash()
|
|
|
|
bc, err := newChain()
|
|
handleError("can't initialize blockchain", err)
|
|
|
|
nbVals, err := bc.GetNextBlockValidators()
|
|
handleError("can't get next block validators", err)
|
|
valScript, err := smartcontract.CreateDefaultMultiSigRedeemScript(nbVals)
|
|
handleError("can't create verification script", err)
|
|
lastBlock, err := bc.GetBlock(bc.GetHeaderHash(int(bc.BlockHeight())))
|
|
handleError("can't fetch last block", err)
|
|
|
|
txMoveNeo, err := testchain.NewTransferFromOwner(bc, bc.GoverningTokenHash(), h, native.NEOTotalSupply, 0, 2)
|
|
handleError("can't transfer NEO", err)
|
|
txMoveGas, err := testchain.NewTransferFromOwner(bc, bc.UtilityTokenHash(), h, 2_000_000_000_000_000, 0, 2)
|
|
handleError("can't tranfser GAS", err)
|
|
lastBlock = addBlock(bc, lastBlock, valScript, txMoveNeo, txMoveGas)
|
|
|
|
tx, contractHash, _, err := testchain.NewDeployTx(bc, "DumpContract.go", h, strings.NewReader(contract), nil)
|
|
handleError("can't create deploy tx", err)
|
|
tx.NetworkFee = 10_000_000
|
|
tx.ValidUntilBlock = bc.BlockHeight() + 1
|
|
handleError("can't sign deploy tx", acc.SignTx(netmode.UnitTestNet, tx))
|
|
lastBlock = addBlock(bc, lastBlock, valScript, tx)
|
|
|
|
key := make([]byte, 10)
|
|
value := make([]byte, 10)
|
|
nonce := uint32(0)
|
|
|
|
blocksNum := uint32(*blockCount)
|
|
txNum := int(*txPerBlock)
|
|
for i := bc.BlockHeight(); i < blocksNum; i++ {
|
|
txs := make([]*transaction.Transaction, txNum)
|
|
for j := 0; j < txNum; j++ {
|
|
nonce++
|
|
_, err = rand.Read(key)
|
|
handleError("can't get random data for key", err)
|
|
_, err = rand.Read(value)
|
|
handleError("can't get random data for value", err)
|
|
|
|
w := io.NewBufBinWriter()
|
|
emit.AppCall(w.BinWriter, contractHash, "put", callflag.All, key, value)
|
|
handleError("can't create transaction", w.Err)
|
|
|
|
tx := transaction.New(w.Bytes(), 4_040_000)
|
|
tx.ValidUntilBlock = i + 1
|
|
tx.NetworkFee = 4_000_000
|
|
tx.Nonce = nonce
|
|
tx.Signers = []transaction.Signer{{
|
|
Account: h,
|
|
Scopes: transaction.CalledByEntry,
|
|
}}
|
|
handleError("can't sign tx", acc.SignTx(netmode.UnitTestNet, tx))
|
|
|
|
txs[j] = tx
|
|
}
|
|
lastBlock = addBlock(bc, lastBlock, valScript, txs...)
|
|
}
|
|
|
|
w := io.NewBinWriterFromIO(outStream)
|
|
w.WriteU32LE(bc.BlockHeight() + 1)
|
|
handleError("error during dump", chaindump.Dump(bc, w, 0, bc.BlockHeight()+1))
|
|
}
|
|
|
|
func handleError(msg string, err error) {
|
|
if err != nil {
|
|
fmt.Printf("%s: %v\n", msg, err)
|
|
os.Exit(1)
|
|
}
|
|
}
|
|
|
|
func newChain() (*core.Blockchain, error) {
|
|
unitTestNetCfg, err := config.Load("./config", netmode.UnitTestNet)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
unitTestNetCfg.ProtocolConfiguration.VerifyBlocks = false
|
|
zapCfg := zap.NewDevelopmentConfig()
|
|
zapCfg.Level = zap.NewAtomicLevelAt(zapcore.InfoLevel)
|
|
log, err := zapCfg.Build()
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
chain, err := core.NewBlockchain(storage.NewMemoryStore(), unitTestNetCfg.ProtocolConfiguration, log)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
go chain.Run()
|
|
return chain, nil
|
|
}
|
|
|
|
func addBlock(bc *core.Blockchain, lastBlock *block.Block, script []byte, txs ...*transaction.Transaction) *block.Block {
|
|
b, err := newBlock(bc, lastBlock, script, txs...)
|
|
if err != nil {
|
|
handleError("can't create block", err)
|
|
}
|
|
if err := bc.AddBlock(b); err != nil {
|
|
handleError("can't add block", err)
|
|
}
|
|
return b
|
|
}
|
|
|
|
func newBlock(bc *core.Blockchain, lastBlock *block.Block, script []byte, txs ...*transaction.Transaction) (*block.Block, error) {
|
|
witness := transaction.Witness{VerificationScript: script}
|
|
b := &block.Block{
|
|
Header: block.Header{
|
|
PrevHash: lastBlock.Hash(),
|
|
Timestamp: uint64(time.Now().UTC().Unix())*1000 + uint64(lastBlock.Index),
|
|
Index: lastBlock.Index + 1,
|
|
NextConsensus: witness.ScriptHash(),
|
|
Script: witness,
|
|
},
|
|
Transactions: txs,
|
|
}
|
|
if bc.GetConfig().StateRootInHeader {
|
|
sr, err := bc.GetStateModule().GetStateRoot(bc.BlockHeight())
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
b.StateRootEnabled = true
|
|
b.PrevStateRoot = sr.Root
|
|
}
|
|
b.RebuildMerkleRoot()
|
|
b.Script.InvocationScript = testchain.Sign(b)
|
|
return b, nil
|
|
}
|