neo-go/scripts/gendump/main.go
Roman Khimov 7589733017 config: add a special Blockchain type to configure Blockchain
And include some node-specific configurations there with backwards
compatibility. Note that in the future we'll remove Ledger's
fields from the ProtocolConfiguration and it'll be possible to access them in
Blockchain directly (not via .Ledger).

The other option tried was using two configuration types separately, but that
incurs more changes to the codebase, single structure that behaves almost like
the old one is better for backwards compatibility.

Fixes #2676.
2022-12-07 17:35:53 +03:00

184 lines
5.5 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/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(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)
script, err := smartcontract.CreateCallScript(contractHash, "put", key, value)
handleError("can't create transaction", err)
tx := transaction.New(script, 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.ApplicationConfiguration.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.Blockchain(), 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
}