From 67f26859a88edb201d1c6fa422b3fbeecf92d2bb Mon Sep 17 00:00:00 2001 From: Evgenii Stratonikov Date: Mon, 23 Nov 2020 14:09:45 +0300 Subject: [PATCH] scripts: implement script for creating dumps This is useful for creating dumps providing various load to benchmark restore or check compatibility with C# nodes. Related #1472. --- internal/testchain/transaction.go | 88 ++++++++++++++ pkg/core/blockchain_test.go | 22 ++-- pkg/core/helper_test.go | 63 ++-------- pkg/core/native_contract_test.go | 9 +- pkg/core/native_designate_test.go | 4 +- pkg/core/native_neo_test.go | 4 +- pkg/core/native_oracle_test.go | 2 +- pkg/core/native_policy_test.go | 3 +- scripts/gendump/main.go | 193 ++++++++++++++++++++++++++++++ 9 files changed, 312 insertions(+), 76 deletions(-) create mode 100644 internal/testchain/transaction.go create mode 100644 scripts/gendump/main.go diff --git a/internal/testchain/transaction.go b/internal/testchain/transaction.go new file mode 100644 index 000000000..d2a37a134 --- /dev/null +++ b/internal/testchain/transaction.go @@ -0,0 +1,88 @@ +package testchain + +import ( + "encoding/json" + gio "io" + + "github.com/nspcc-dev/neo-go/pkg/compiler" + "github.com/nspcc-dev/neo-go/pkg/config/netmode" + "github.com/nspcc-dev/neo-go/pkg/core/blockchainer" + "github.com/nspcc-dev/neo-go/pkg/core/fee" + "github.com/nspcc-dev/neo-go/pkg/core/interop/interopnames" + "github.com/nspcc-dev/neo-go/pkg/core/native" + "github.com/nspcc-dev/neo-go/pkg/core/transaction" + "github.com/nspcc-dev/neo-go/pkg/io" + "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/opcode" +) + +var ( + ownerHash = MultisigScriptHash() + ownerScript = MultisigVerificationScript() +) + +// NewTransferFromOwner returns transaction transfering funds from NEO and GAS owner. +func NewTransferFromOwner(bc blockchainer.Blockchainer, contractHash, to util.Uint160, amount int64, + nonce, validUntil uint32) (*transaction.Transaction, error) { + w := io.NewBufBinWriter() + emit.AppCallWithOperationAndArgs(w.BinWriter, contractHash, "transfer", ownerHash, to, amount, nil) + emit.Opcodes(w.BinWriter, opcode.ASSERT) + if w.Err != nil { + return nil, w.Err + } + + script := w.Bytes() + tx := transaction.New(netmode.UnitTestNet, script, 10000000) + tx.ValidUntilBlock = validUntil + tx.Nonce = nonce + tx.Signers = []transaction.Signer{{ + Account: ownerHash, + Scopes: transaction.CalledByEntry, + AllowedContracts: nil, + AllowedGroups: nil, + }} + return tx, SignTx(bc, tx) +} + +// NewDeployTx returns new deployment tx for contract with name with Go code read from r. +func NewDeployTx(name string, r gio.Reader) (*transaction.Transaction, []byte, error) { + avm, di, err := compiler.CompileWithDebugInfo(name, r) + if err != nil { + return nil, nil, err + } + + w := io.NewBufBinWriter() + m, err := di.ConvertToManifest(name, nil) + if err != nil { + return nil, nil, err + } + bs, err := json.Marshal(m) + if err != nil { + return nil, nil, err + } + emit.Bytes(w.BinWriter, bs) + emit.Bytes(w.BinWriter, avm) + emit.Syscall(w.BinWriter, interopnames.SystemContractCreate) + if w.Err != nil { + return nil, nil, err + } + return transaction.New(Network(), w.Bytes(), 100*native.GASFactor), avm, nil +} + +// SignTx signs provided transactions with validator keys. +func SignTx(bc blockchainer.Blockchainer, txs ...*transaction.Transaction) error { + for _, tx := range txs { + size := io.GetVarSize(tx) + netFee, sizeDelta := fee.Calculate(ownerScript) + tx.NetworkFee += netFee + size += sizeDelta + tx.NetworkFee += int64(size) * bc.FeePerByte() + data := tx.GetSignedPart() + tx.Scripts = []transaction.Witness{{ + InvocationScript: Sign(data), + VerificationScript: ownerScript, + }} + } + return nil +} diff --git a/pkg/core/blockchain_test.go b/pkg/core/blockchain_test.go index e70577a9d..d9dfa0e85 100644 --- a/pkg/core/blockchain_test.go +++ b/pkg/core/blockchain_test.go @@ -133,7 +133,7 @@ func TestAddBlockStateRoot(t *testing.T) { tx := newNEP17Transfer(bc.contracts.NEO.Hash, neoOwner, util.Uint160{}, 1) tx.ValidUntilBlock = bc.BlockHeight() + 1 addSigners(tx) - require.NoError(t, signTx(bc, tx)) + require.NoError(t, testchain.SignTx(bc, tx)) lastBlock := bc.topBlock.Load().(*block.Block) b := newBlock(bc.config, lastBlock.Index+1, lastBlock.Hash(), tx) @@ -159,7 +159,7 @@ func TestAddBadBlock(t *testing.T) { Account: testchain.MultisigScriptHash(), Scopes: transaction.None, }} - require.NoError(t, signTx(bc, tx)) + require.NoError(t, testchain.SignTx(bc, tx)) b1 := bc.newBlock(tx) require.Error(t, bc.AddBlock(b1)) @@ -179,7 +179,7 @@ func TestAddBadBlock(t *testing.T) { Account: testchain.MultisigScriptHash(), Scopes: transaction.None, }} - require.NoError(t, signTx(bc, tx)) + require.NoError(t, testchain.SignTx(bc, tx)) require.NoError(t, bc.PoolTx(tx)) bc.config.VerifyTransactions = true bc.config.VerifyBlocks = true @@ -192,7 +192,7 @@ func TestGetHeader(t *testing.T) { tx := transaction.New(netmode.UnitTestNet, []byte{byte(opcode.PUSH1)}, 0) tx.ValidUntilBlock = bc.BlockHeight() + 1 addSigners(tx) - assert.Nil(t, signTx(bc, tx)) + assert.Nil(t, testchain.SignTx(bc, tx)) block := bc.newBlock(tx) err := bc.AddBlock(block) assert.Nil(t, err) @@ -277,7 +277,7 @@ func TestVerifyTx(t *testing.T) { txMove := bc.newTestTx(neoOwner, w.Bytes()) txMove.SystemFee = 1_000_000_000 - require.NoError(t, signTx(bc, txMove)) + require.NoError(t, testchain.SignTx(bc, txMove)) b := bc.newBlock(txMove) require.NoError(t, bc.AddBlock(b)) @@ -805,12 +805,12 @@ func TestMemPoolRemoval(t *testing.T) { notAddedTxes := make([]*transaction.Transaction, notAdded) for i := range addedTxes { addedTxes[i] = bc.newTestTx(testchain.MultisigScriptHash(), []byte{byte(opcode.PUSH1)}) - require.NoError(t, signTx(bc, addedTxes[i])) + require.NoError(t, testchain.SignTx(bc, addedTxes[i])) require.NoError(t, bc.PoolTx(addedTxes[i])) } for i := range notAddedTxes { notAddedTxes[i] = bc.newTestTx(testchain.MultisigScriptHash(), []byte{byte(opcode.PUSH1)}) - require.NoError(t, signTx(bc, notAddedTxes[i])) + require.NoError(t, testchain.SignTx(bc, notAddedTxes[i])) require.NoError(t, bc.PoolTx(notAddedTxes[i])) } b := bc.newBlock(addedTxes...) @@ -854,7 +854,7 @@ func TestGetTransaction(t *testing.T) { Account: testchain.MultisigScriptHash(), Scopes: transaction.CalledByEntry, }} - require.NoError(t, signTx(bc, tx1, tx2)) + require.NoError(t, testchain.SignTx(bc, tx1, tx2)) b1 := bc.newBlock(tx1) assert.Nil(t, bc.AddBlock(b1)) @@ -955,7 +955,7 @@ func TestSubscriptions(t *testing.T) { txGood1.Signers = []transaction.Signer{{Account: neoOwner}} txGood1.Nonce = 1 txGood1.ValidUntilBlock = 1024 - require.NoError(t, signTx(bc, txGood1)) + require.NoError(t, testchain.SignTx(bc, txGood1)) // Reset() reuses the script buffer and we need to keep scripts. script = io.NewBufBinWriter() @@ -967,7 +967,7 @@ func TestSubscriptions(t *testing.T) { txBad.Signers = []transaction.Signer{{Account: neoOwner}} txBad.Nonce = 2 txBad.ValidUntilBlock = 1024 - require.NoError(t, signTx(bc, txBad)) + require.NoError(t, testchain.SignTx(bc, txBad)) script = io.NewBufBinWriter() emit.Bytes(script.BinWriter, []byte("yay! yay! yay!")) @@ -977,7 +977,7 @@ func TestSubscriptions(t *testing.T) { txGood2.Signers = []transaction.Signer{{Account: neoOwner}} txGood2.Nonce = 3 txGood2.ValidUntilBlock = 1024 - require.NoError(t, signTx(bc, txGood2)) + require.NoError(t, testchain.SignTx(bc, txGood2)) invBlock := newBlock(bc.config, bc.BlockHeight()+1, bc.CurrentHeaderHash(), txGood1, txBad, txGood2) require.NoError(t, bc.AddBlock(invBlock)) diff --git a/pkg/core/helper_test.go b/pkg/core/helper_test.go index eac68e24d..50323e3e7 100644 --- a/pkg/core/helper_test.go +++ b/pkg/core/helper_test.go @@ -13,12 +13,10 @@ import ( "github.com/nspcc-dev/neo-go/internal/testchain" "github.com/nspcc-dev/neo-go/internal/testserdes" - "github.com/nspcc-dev/neo-go/pkg/compiler" "github.com/nspcc-dev/neo-go/pkg/config" "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/fee" - "github.com/nspcc-dev/neo-go/pkg/core/interop/interopnames" "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" @@ -239,27 +237,13 @@ func initBasicChain(t *testing.T, bc *Blockchain) { require.Equal(t, big.NewInt(5000_0000), bc.GetUtilityTokenBalance(priv0ScriptHash)) // gas bounty // Move some NEO to one simple account. - txMoveNeo := newNEP17Transfer(neoHash, neoOwner, priv0ScriptHash, neoAmount) - txMoveNeo.ValidUntilBlock = validUntilBlock - txMoveNeo.Nonce = getNextNonce() - txMoveNeo.Signers = []transaction.Signer{{ - Account: neoOwner, - Scopes: transaction.CalledByEntry, - AllowedContracts: nil, - AllowedGroups: nil, - }} - require.NoError(t, signTx(bc, txMoveNeo)) + txMoveNeo, err := testchain.NewTransferFromOwner(bc, neoHash, priv0ScriptHash, neoAmount, getNextNonce(), validUntilBlock) + require.NoError(t, err) // Move some GAS to one simple account. - txMoveGas := newNEP17Transfer(gasHash, neoOwner, priv0ScriptHash, int64(util.Fixed8FromInt64(1000))) - txMoveGas.ValidUntilBlock = validUntilBlock - txMoveGas.Nonce = getNextNonce() - txMoveGas.Signers = []transaction.Signer{{ - Account: neoOwner, - Scopes: transaction.CalledByEntry, - AllowedContracts: nil, - AllowedGroups: nil, - }} - require.NoError(t, signTx(bc, txMoveGas)) + txMoveGas, err := testchain.NewTransferFromOwner(bc, gasHash, priv0ScriptHash, int64(util.Fixed8FromInt64(1000)), + getNextNonce(), validUntilBlock) + require.NoError(t, err) + b := bc.newBlock(txMoveNeo, txMoveGas) require.NoError(t, bc.AddBlock(b)) t.Logf("Block1 hash: %s", b.Hash().StringLE()) @@ -392,22 +376,12 @@ func newNEP17Transfer(sc, from, to util.Uint160, amount int64) *transaction.Tran func newDeployTx(t *testing.T, name, ctrName string) (*transaction.Transaction, []byte) { c, err := ioutil.ReadFile(name) require.NoError(t, err) - avm, di, err := compiler.CompileWithDebugInfo(name, bytes.NewReader(c)) + tx, avm, err := testchain.NewDeployTx(ctrName, bytes.NewReader(c)) require.NoError(t, err) t.Logf("contractHash (%s): %s", name, hash.Hash160(avm).StringLE()) t.Logf("contractScript: %x", avm) - script := io.NewBufBinWriter() - m, err := di.ConvertToManifest(ctrName, nil) - require.NoError(t, err) - bs, err := json.Marshal(m) - require.NoError(t, err) - emit.Bytes(script.BinWriter, bs) - emit.Bytes(script.BinWriter, avm) - emit.Syscall(script.BinWriter, interopnames.SystemContractCreate) - txScript := script.Bytes() - - return transaction.New(testchain.Network(), txScript, 100*native.GASFactor), avm + return tx, avm } func addSigners(txs ...*transaction.Transaction) { @@ -421,27 +395,6 @@ func addSigners(txs ...*transaction.Transaction) { } } -func signTx(bc *Blockchain, txs ...*transaction.Transaction) error { - validators := bc.GetStandByValidators() - rawScript, err := smartcontract.CreateDefaultMultiSigRedeemScript(validators) - if err != nil { - return fmt.Errorf("failed to sign tx: %w", err) - } - for _, tx := range txs { - size := io.GetVarSize(tx) - netFee, sizeDelta := fee.Calculate(rawScript) - tx.NetworkFee += netFee - size += sizeDelta - tx.NetworkFee += int64(size) * bc.FeePerByte() - data := tx.GetSignedPart() - tx.Scripts = []transaction.Witness{{ - InvocationScript: testchain.Sign(data), - VerificationScript: rawScript, - }} - } - return nil -} - func addNetworkFee(bc *Blockchain, tx *transaction.Transaction, sender *wallet.Account) error { size := io.GetVarSize(tx) netFee, sizeDelta := fee.Calculate(sender.Contract.Script) diff --git a/pkg/core/native_contract_test.go b/pkg/core/native_contract_test.go index 02dffe1d1..ac0528f91 100644 --- a/pkg/core/native_contract_test.go +++ b/pkg/core/native_contract_test.go @@ -4,6 +4,7 @@ import ( "math/big" "testing" + "github.com/nspcc-dev/neo-go/internal/testchain" "github.com/nspcc-dev/neo-go/pkg/config/netmode" "github.com/nspcc-dev/neo-go/pkg/core/dao" "github.com/nspcc-dev/neo-go/pkg/core/interop" @@ -164,13 +165,13 @@ func TestNativeContract_Invoke(t *testing.T) { validUntil := chain.blockHeight + 1 tx.ValidUntilBlock = validUntil addSigners(tx) - require.NoError(t, signTx(chain, tx)) + require.NoError(t, testchain.SignTx(chain, tx)) // Enough for Call and other opcodes, but not enough for "sum" call. tx2 := transaction.New(chain.GetConfig().Magic, script, testSumPrice*2+8000) tx2.ValidUntilBlock = chain.blockHeight + 1 addSigners(tx2) - require.NoError(t, signTx(chain, tx2)) + require.NoError(t, testchain.SignTx(chain, tx2)) b := chain.newBlock(tx, tx2) require.NoError(t, chain.AddBlock(b)) @@ -262,7 +263,7 @@ func TestNativeContract_InvokeOtherContract(t *testing.T) { validUntil := chain.blockHeight + 1 tx.ValidUntilBlock = validUntil addSigners(tx) - require.NoError(t, signTx(chain, tx)) + require.NoError(t, testchain.SignTx(chain, tx)) b := chain.newBlock(tx) require.NoError(t, chain.AddBlock(b)) @@ -289,7 +290,7 @@ func TestAllContractsHaveName(t *testing.T) { tx := transaction.New(netmode.UnitTestNet, w.Bytes(), 1015570) tx.ValidUntilBlock = bc.blockHeight + 1 addSigners(tx) - require.NoError(t, signTx(bc, tx)) + require.NoError(t, testchain.SignTx(bc, tx)) require.NoError(t, bc.AddBlock(bc.newBlock(tx))) aers, err := bc.GetAppExecResults(tx.Hash(), trigger.Application) diff --git a/pkg/core/native_designate_test.go b/pkg/core/native_designate_test.go index f29ccdb7c..4c4e78779 100644 --- a/pkg/core/native_designate_test.go +++ b/pkg/core/native_designate_test.go @@ -46,7 +46,7 @@ func (bc *Blockchain) setNodesByRole(t *testing.T, ok bool, r native.Role, nodes Scopes: transaction.CalledByEntry, }, } - require.NoError(t, signTx(bc, tx)) + require.NoError(t, testchain.SignTx(bc, tx)) tx.Scripts = append(tx.Scripts, transaction.Witness{ InvocationScript: testchain.SignCommittee(tx.GetSignedPart()), VerificationScript: testchain.CommitteeVerificationScript(), @@ -77,7 +77,7 @@ func (bc *Blockchain) getNodesByRole(t *testing.T, ok bool, r native.Role, index Scopes: transaction.None, }, } - require.NoError(t, signTx(bc, tx)) + require.NoError(t, testchain.SignTx(bc, tx)) require.NoError(t, bc.AddBlock(bc.newBlock(tx))) aer, err := bc.GetAppExecResults(tx.Hash(), trigger.Application) diff --git a/pkg/core/native_neo_test.go b/pkg/core/native_neo_test.go index fa25354e3..de83f2fc5 100644 --- a/pkg/core/native_neo_test.go +++ b/pkg/core/native_neo_test.go @@ -87,7 +87,7 @@ func TestNEO_Vote(t *testing.T) { tx := transaction.New(netmode.UnitTestNet, w.Bytes(), 1000_000_000) tx.ValidUntilBlock = bc.BlockHeight() + 1 setSigner(tx, testchain.MultisigScriptHash()) - require.NoError(t, signTx(bc, tx)) + require.NoError(t, testchain.SignTx(bc, tx)) txs = append(txs, tx) } require.NoError(t, bc.AddBlock(bc.newBlock(txs...))) @@ -318,7 +318,7 @@ func TestNEO_TransferOnPayment(t *testing.T) { tx.NetworkFee = 10_000_000 tx.ValidUntilBlock = bc.BlockHeight() + 1 addSigners(tx) - require.NoError(t, signTx(bc, tx)) + require.NoError(t, testchain.SignTx(bc, tx)) require.NoError(t, bc.AddBlock(bc.newBlock(tx))) aer, err := bc.GetAppExecResults(tx.Hash(), trigger.Application) diff --git a/pkg/core/native_oracle_test.go b/pkg/core/native_oracle_test.go index 9e4bd34ce..7f0612044 100644 --- a/pkg/core/native_oracle_test.go +++ b/pkg/core/native_oracle_test.go @@ -104,7 +104,7 @@ func putOracleRequest(t *testing.T, h util.Uint160, bc *Blockchain, tx.ValidUntilBlock = bc.BlockHeight() + 1 tx.NetworkFee = 1_000_000 setSigner(tx, testchain.MultisigScriptHash()) - require.NoError(t, signTx(bc, tx)) + require.NoError(t, testchain.SignTx(bc, tx)) require.NoError(t, bc.AddBlock(bc.newBlock(tx))) return tx.Hash() } diff --git a/pkg/core/native_policy_test.go b/pkg/core/native_policy_test.go index f9a04eb66..496c6b1b5 100644 --- a/pkg/core/native_policy_test.go +++ b/pkg/core/native_policy_test.go @@ -5,6 +5,7 @@ import ( "testing" "github.com/nspcc-dev/neo-go/internal/random" + "github.com/nspcc-dev/neo-go/internal/testchain" "github.com/nspcc-dev/neo-go/pkg/core/block" "github.com/nspcc-dev/neo-go/pkg/core/native" "github.com/nspcc-dev/neo-go/pkg/core/state" @@ -231,7 +232,7 @@ func invokeNativePolicyMethod(chain *Blockchain, method string, args ...interfac validUntil := chain.blockHeight + 1 tx.ValidUntilBlock = validUntil addSigners(tx) - err := signTx(chain, tx) + err := testchain.SignTx(chain, tx) if err != nil { return nil, err } diff --git a/scripts/gendump/main.go b/scripts/gendump/main.go new file mode 100644 index 000000000..1ce76be2c --- /dev/null +++ b/scripts/gendump/main.go @@ -0,0 +1,193 @@ +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/crypto/hash" + "github.com/nspcc-dev/neo-go/pkg/io" + "github.com/nspcc-dev/neo-go/pkg/smartcontract" + "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) + + valScript, err := smartcontract.CreateDefaultMultiSigRedeemScript(bc.GetStandByValidators()) + 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, avm, err := testchain.NewDeployTx("DumpContract", strings.NewReader(contract)) + handleError("can't create deploy tx", err) + tx.Signers = []transaction.Signer{{ + Account: h, + Scopes: transaction.CalledByEntry, + }} + tx.NetworkFee = 10_000_000 + tx.ValidUntilBlock = bc.BlockHeight() + 1 + handleError("can't sign deploy tx", acc.SignTx(tx)) + lastBlock = addBlock(bc, lastBlock, valScript, tx) + + contractHash := hash.Hash160(avm) + 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++ + rand.Read(key) + rand.Read(value) + + w := io.NewBufBinWriter() + emit.AppCallWithOperationAndArgs(w.BinWriter, contractHash, "put", key, value) + handleError("can't create transaction", w.Err) + + tx := transaction.New(netmode.UnitTestNet, w.Bytes(), 4_000_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(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{ + Base: block.Base{ + Network: netmode.UnitTestNet, + PrevHash: lastBlock.Hash(), + Timestamp: uint64(time.Now().UTC().Unix())*1000 + uint64(lastBlock.Index), + Index: lastBlock.Index + 1, + NextConsensus: witness.ScriptHash(), + Script: witness, + }, + ConsensusData: block.ConsensusData{ + PrimaryIndex: 0, + Nonce: 1111, + }, + Transactions: txs, + } + if bc.GetConfig().StateRootInHeader { + sr, err := bc.GetStateRoot(bc.BlockHeight()) + if err != nil { + return nil, err + } + b.StateRootEnabled = true + b.PrevStateRoot = sr.Root + } + b.RebuildMerkleRoot() + b.Script.InvocationScript = testchain.Sign(b.GetSignedPart()) + return b, nil +}