github.com/nspcc-dev/neo-go@v0.105.2-0.20240517133400-6be757af3eba/scripts/gendump/main.go (about)

     1  package main
     2  
     3  import (
     4  	"crypto/rand"
     5  	"errors"
     6  	"flag"
     7  	"fmt"
     8  	"os"
     9  	"strings"
    10  	"time"
    11  
    12  	"github.com/nspcc-dev/neo-go/internal/testchain"
    13  	"github.com/nspcc-dev/neo-go/pkg/config"
    14  	"github.com/nspcc-dev/neo-go/pkg/config/netmode"
    15  	"github.com/nspcc-dev/neo-go/pkg/core"
    16  	"github.com/nspcc-dev/neo-go/pkg/core/block"
    17  	"github.com/nspcc-dev/neo-go/pkg/core/chaindump"
    18  	"github.com/nspcc-dev/neo-go/pkg/core/native"
    19  	"github.com/nspcc-dev/neo-go/pkg/core/storage"
    20  	"github.com/nspcc-dev/neo-go/pkg/core/transaction"
    21  	"github.com/nspcc-dev/neo-go/pkg/io"
    22  	"github.com/nspcc-dev/neo-go/pkg/smartcontract"
    23  	"github.com/nspcc-dev/neo-go/pkg/wallet"
    24  	"go.uber.org/zap"
    25  	"go.uber.org/zap/zapcore"
    26  )
    27  
    28  // Takes 1 minute for 100 tx per block and 5000 blocks.
    29  const (
    30  	defaultBlockCount = 5000
    31  	defaultTxPerBlock = 100
    32  )
    33  
    34  var (
    35  	outFile    = flag.String("out", "", "filename to write dump to")
    36  	blockCount = flag.Uint("blocks", defaultBlockCount, "number of blocks to generate")
    37  	txPerBlock = flag.Uint("txs", defaultTxPerBlock, "number of blocks to generate")
    38  )
    39  
    40  func main() {
    41  	flag.Parse()
    42  
    43  	if *outFile == "" {
    44  		handleError("", errors.New("output file is not provided"))
    45  	}
    46  	outStream, err := os.Create(*outFile) // fail early
    47  	handleError("can't open output file", err)
    48  	defer outStream.Close()
    49  
    50  	const contract = `
    51  	package contract
    52  	import "github.com/nspcc-dev/neo-go/pkg/interop/storage"
    53  	var ctx = storage.GetContext()
    54  	func Put(key, value []byte) {
    55  		storage.Put(ctx, key, value)
    56  	}`
    57  
    58  	acc, err := wallet.NewAccount()
    59  	handleError("can't create new account", err)
    60  	h := acc.Contract.ScriptHash()
    61  
    62  	bc, err := newChain()
    63  	handleError("can't initialize blockchain", err)
    64  
    65  	nbVals, err := bc.GetNextBlockValidators()
    66  	handleError("can't get next block validators", err)
    67  	valScript, err := smartcontract.CreateDefaultMultiSigRedeemScript(nbVals)
    68  	handleError("can't create verification script", err)
    69  	lastBlock, err := bc.GetBlock(bc.GetHeaderHash(bc.BlockHeight()))
    70  	handleError("can't fetch last block", err)
    71  
    72  	txMoveNeo, err := testchain.NewTransferFromOwner(bc, bc.GoverningTokenHash(), h, native.NEOTotalSupply, 0, 2)
    73  	handleError("can't transfer NEO", err)
    74  	txMoveGas, err := testchain.NewTransferFromOwner(bc, bc.UtilityTokenHash(), h, 2_000_000_000_000_000, 0, 2)
    75  	handleError("can't tranfser GAS", err)
    76  	lastBlock = addBlock(bc, lastBlock, valScript, txMoveNeo, txMoveGas)
    77  
    78  	tx, contractHash, _, err := testchain.NewDeployTx(bc, "DumpContract.go", h, strings.NewReader(contract), nil)
    79  	handleError("can't create deploy tx", err)
    80  	tx.NetworkFee = 10_000_000
    81  	tx.ValidUntilBlock = bc.BlockHeight() + 1
    82  	handleError("can't sign deploy tx", acc.SignTx(netmode.UnitTestNet, tx))
    83  	lastBlock = addBlock(bc, lastBlock, valScript, tx)
    84  
    85  	key := make([]byte, 10)
    86  	value := make([]byte, 10)
    87  	nonce := uint32(0)
    88  
    89  	blocksNum := uint32(*blockCount)
    90  	txNum := int(*txPerBlock)
    91  	for i := bc.BlockHeight(); i < blocksNum; i++ {
    92  		txs := make([]*transaction.Transaction, txNum)
    93  		for j := 0; j < txNum; j++ {
    94  			nonce++
    95  			_, err = rand.Read(key)
    96  			handleError("can't get random data for key", err)
    97  			_, err = rand.Read(value)
    98  			handleError("can't get random data for value", err)
    99  
   100  			script, err := smartcontract.CreateCallScript(contractHash, "put", key, value)
   101  			handleError("can't create transaction", err)
   102  
   103  			tx := transaction.New(script, 4_040_000)
   104  			tx.ValidUntilBlock = i + 1
   105  			tx.NetworkFee = 4_000_000
   106  			tx.Nonce = nonce
   107  			tx.Signers = []transaction.Signer{{
   108  				Account: h,
   109  				Scopes:  transaction.CalledByEntry,
   110  			}}
   111  			handleError("can't sign tx", acc.SignTx(netmode.UnitTestNet, tx))
   112  
   113  			txs[j] = tx
   114  		}
   115  		lastBlock = addBlock(bc, lastBlock, valScript, txs...)
   116  	}
   117  
   118  	w := io.NewBinWriterFromIO(outStream)
   119  	w.WriteU32LE(bc.BlockHeight() + 1)
   120  	handleError("error during dump", chaindump.Dump(bc, w, 0, bc.BlockHeight()+1))
   121  }
   122  
   123  func handleError(msg string, err error) {
   124  	if err != nil {
   125  		fmt.Printf("%s: %v\n", msg, err)
   126  		os.Exit(1)
   127  	}
   128  }
   129  
   130  func newChain() (*core.Blockchain, error) {
   131  	unitTestNetCfg, err := config.Load("./config", netmode.UnitTestNet)
   132  	if err != nil {
   133  		return nil, err
   134  	}
   135  	unitTestNetCfg.ApplicationConfiguration.SkipBlockVerification = true
   136  	zapCfg := zap.NewDevelopmentConfig()
   137  	zapCfg.Level = zap.NewAtomicLevelAt(zapcore.InfoLevel)
   138  	log, err := zapCfg.Build()
   139  	if err != nil {
   140  		return nil, err
   141  	}
   142  	chain, err := core.NewBlockchain(storage.NewMemoryStore(), unitTestNetCfg.Blockchain(), log)
   143  	if err != nil {
   144  		return nil, err
   145  	}
   146  	go chain.Run()
   147  	return chain, nil
   148  }
   149  
   150  func addBlock(bc *core.Blockchain, lastBlock *block.Block, script []byte, txs ...*transaction.Transaction) *block.Block {
   151  	b, err := newBlock(bc, lastBlock, script, txs...)
   152  	if err != nil {
   153  		handleError("can't create block", err)
   154  	}
   155  	if err := bc.AddBlock(b); err != nil {
   156  		handleError("can't add block", err)
   157  	}
   158  	return b
   159  }
   160  
   161  func newBlock(bc *core.Blockchain, lastBlock *block.Block, script []byte, txs ...*transaction.Transaction) (*block.Block, error) {
   162  	witness := transaction.Witness{VerificationScript: script}
   163  	b := &block.Block{
   164  		Header: block.Header{
   165  			PrevHash:      lastBlock.Hash(),
   166  			Timestamp:     uint64(time.Now().UTC().Unix())*1000 + uint64(lastBlock.Index),
   167  			Index:         lastBlock.Index + 1,
   168  			NextConsensus: witness.ScriptHash(),
   169  			Script:        witness,
   170  		},
   171  		Transactions: txs,
   172  	}
   173  	if bc.GetConfig().StateRootInHeader {
   174  		sr, err := bc.GetStateModule().GetStateRoot(bc.BlockHeight())
   175  		if err != nil {
   176  			return nil, err
   177  		}
   178  		b.StateRootEnabled = true
   179  		b.PrevStateRoot = sr.Root
   180  	}
   181  	b.RebuildMerkleRoot()
   182  	b.Script.InvocationScript = testchain.Sign(b)
   183  	return b, nil
   184  }