2021-10-26 11:28:14 +00:00
|
|
|
package tests
|
|
|
|
|
|
|
|
import (
|
2023-11-07 10:58:16 +00:00
|
|
|
"context"
|
|
|
|
"net/http"
|
|
|
|
"os"
|
2021-10-26 11:28:14 +00:00
|
|
|
"testing"
|
2023-11-07 10:58:16 +00:00
|
|
|
"time"
|
2021-10-26 11:28:14 +00:00
|
|
|
|
2023-11-07 10:58:16 +00:00
|
|
|
"github.com/nspcc-dev/neo-go/pkg/config"
|
|
|
|
"github.com/nspcc-dev/neo-go/pkg/consensus"
|
|
|
|
"github.com/nspcc-dev/neo-go/pkg/core"
|
2022-11-17 15:30:21 +00:00
|
|
|
"github.com/nspcc-dev/neo-go/pkg/core/interop/storage"
|
2023-11-07 10:58:16 +00:00
|
|
|
"github.com/nspcc-dev/neo-go/pkg/core/state"
|
|
|
|
corestate "github.com/nspcc-dev/neo-go/pkg/core/stateroot"
|
|
|
|
"github.com/nspcc-dev/neo-go/pkg/core/storage/dbconfig"
|
2021-10-26 11:28:14 +00:00
|
|
|
"github.com/nspcc-dev/neo-go/pkg/neotest"
|
|
|
|
"github.com/nspcc-dev/neo-go/pkg/neotest/chain"
|
2023-11-07 10:58:16 +00:00
|
|
|
"github.com/nspcc-dev/neo-go/pkg/network"
|
|
|
|
"github.com/nspcc-dev/neo-go/pkg/rpcclient"
|
|
|
|
"github.com/nspcc-dev/neo-go/pkg/services/rpcsrv"
|
|
|
|
"github.com/nspcc-dev/neo-go/pkg/services/stateroot"
|
|
|
|
"github.com/nspcc-dev/neo-go/pkg/smartcontract/trigger"
|
|
|
|
"github.com/nspcc-dev/neo-go/pkg/util"
|
2022-11-17 15:30:21 +00:00
|
|
|
"github.com/nspcc-dev/neo-go/pkg/vm/stackitem"
|
2023-11-07 10:58:16 +00:00
|
|
|
"github.com/stretchr/testify/require"
|
|
|
|
"go.uber.org/zap"
|
2021-10-26 11:28:14 +00:00
|
|
|
)
|
|
|
|
|
2023-11-07 10:58:16 +00:00
|
|
|
type awaiter struct {
|
|
|
|
ctx context.Context
|
|
|
|
t *testing.T
|
|
|
|
rpc *rpcclient.Client
|
|
|
|
}
|
|
|
|
|
|
|
|
func (a awaiter) await(tx util.Uint256, vub uint32, err error) *state.AppExecResult {
|
|
|
|
require.NoError(a.t, err)
|
|
|
|
return await(a.ctx, a.t, a.rpc, tx, vub)
|
|
|
|
}
|
|
|
|
|
|
|
|
const nodeWallet = `
|
|
|
|
{
|
|
|
|
"version": "3.0",
|
|
|
|
"accounts": [
|
|
|
|
{
|
|
|
|
"address": "Nhfg3TbpwogLvDGVvAvqyThbsHgoSUKwtn",
|
|
|
|
"key": "6PYM8VdX2BSm7BSXKzV4Fz6S3R9cDLLWNrD9nMjxW352jEv3fsC8N3wNLY",
|
|
|
|
"label": "",
|
|
|
|
"contract": {
|
|
|
|
"script": "DCECs2Ir9AF73+MXxYrtX0x1PyBrfbiWBG+n13S7xL9/jcJBVuezJw==",
|
|
|
|
"parameters": [
|
|
|
|
{
|
|
|
|
"name": "parameter0",
|
|
|
|
"type": "Signature"
|
|
|
|
}
|
|
|
|
],
|
|
|
|
"deployed": false
|
|
|
|
},
|
|
|
|
"lock": false,
|
|
|
|
"isdefault": false
|
|
|
|
}
|
|
|
|
],
|
|
|
|
"scrypt": {
|
|
|
|
"n": 16384,
|
|
|
|
"r": 8,
|
|
|
|
"p": 8
|
|
|
|
},
|
|
|
|
"extra": {
|
|
|
|
"Tokens": null
|
|
|
|
}
|
|
|
|
}
|
|
|
|
`
|
|
|
|
|
2022-11-17 15:30:21 +00:00
|
|
|
func iteratorToArray(iter *storage.Iterator) []stackitem.Item {
|
|
|
|
stackItems := make([]stackitem.Item, 0)
|
|
|
|
for iter.Next() {
|
|
|
|
stackItems = append(stackItems, iter.Value())
|
|
|
|
}
|
|
|
|
return stackItems
|
|
|
|
}
|
|
|
|
|
2021-10-26 11:28:14 +00:00
|
|
|
func newExecutor(t *testing.T) *neotest.Executor {
|
|
|
|
bc, acc := chain.NewSingle(t)
|
|
|
|
return neotest.NewExecutor(t, bc, acc, acc)
|
|
|
|
}
|
2023-11-07 10:58:16 +00:00
|
|
|
|
|
|
|
func initTmpWallet(t *testing.T) string {
|
|
|
|
f, err := os.CreateTemp("", "tmp-neo-go-wallet")
|
|
|
|
require.NoError(t, err)
|
|
|
|
|
|
|
|
_, err = f.WriteString(nodeWallet)
|
|
|
|
require.NoError(t, err)
|
|
|
|
|
|
|
|
err = f.Close()
|
|
|
|
require.NoError(t, err)
|
|
|
|
return f.Name()
|
|
|
|
}
|
|
|
|
|
|
|
|
func await(ctx context.Context, t *testing.T, rpc *rpcclient.Client, tx util.Uint256, vub uint32) *state.AppExecResult {
|
|
|
|
waitCtx, waitCancel := context.WithTimeout(ctx, 5*time.Second)
|
|
|
|
defer waitCancel()
|
|
|
|
|
|
|
|
for {
|
|
|
|
select {
|
|
|
|
case <-waitCtx.Done():
|
|
|
|
require.NoError(t, waitCtx.Err())
|
|
|
|
return nil
|
|
|
|
default:
|
|
|
|
bc, err := rpc.GetBlockCount()
|
|
|
|
require.NoError(t, err)
|
|
|
|
|
|
|
|
tr := trigger.Application
|
|
|
|
if log, err := rpc.GetApplicationLog(tx, &tr); err == nil {
|
|
|
|
return &state.AppExecResult{
|
|
|
|
Container: log.Container,
|
|
|
|
Execution: log.Executions[0],
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
require.LessOrEqual(t, bc, vub, "vub is expired")
|
|
|
|
time.Sleep(100 * time.Millisecond)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func neogoCfg() config.Config {
|
|
|
|
return config.Config{
|
|
|
|
ProtocolConfiguration: config.ProtocolConfiguration{},
|
|
|
|
ApplicationConfiguration: config.ApplicationConfiguration{
|
|
|
|
RPC: config.RPC{
|
|
|
|
BasicService: config.BasicService{
|
|
|
|
Enabled: true,
|
|
|
|
// See how tests are done in the neo-go itself:
|
|
|
|
// https://github.com/nspcc-dev/neo-go/blob/5fc61be5f6c5349d8de8b61967380feee6b51c55/config/protocol.unit_testnet.single.yml#L61
|
|
|
|
Addresses: []string{"localhost:0"},
|
|
|
|
},
|
|
|
|
MaxGasInvoke: 200_000_000,
|
|
|
|
SessionEnabled: true,
|
|
|
|
MaxIteratorResultItems: 100,
|
|
|
|
SessionPoolSize: 20,
|
|
|
|
SessionExpirationTime: 15,
|
|
|
|
},
|
|
|
|
DBConfiguration: dbconfig.DBConfiguration{
|
|
|
|
Type: dbconfig.InMemoryDB,
|
|
|
|
},
|
|
|
|
},
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func consensusCfg(chain *core.Blockchain, walletAddress string, srv *network.Server) consensus.Config {
|
|
|
|
return consensus.Config{
|
|
|
|
Logger: zap.NewExample(),
|
|
|
|
Broadcast: srv.BroadcastExtensible,
|
|
|
|
BlockQueue: srv.GetBlockQueue(),
|
|
|
|
Chain: chain,
|
|
|
|
ProtocolConfiguration: chain.GetConfig().ProtocolConfiguration,
|
|
|
|
RequestTx: srv.RequestTx,
|
|
|
|
StopTxFlow: srv.StopTxFlow,
|
|
|
|
Wallet: config.Wallet{
|
|
|
|
Path: walletAddress,
|
|
|
|
Password: "one",
|
|
|
|
},
|
|
|
|
TimePerBlock: 100 * time.Millisecond,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func runRPC(ctx context.Context, t *testing.T, chain *core.Blockchain, walletPath string) string {
|
|
|
|
log := zap.NewExample()
|
|
|
|
cfg := neogoCfg()
|
|
|
|
|
|
|
|
srvCfg, err := network.NewServerConfig(cfg)
|
|
|
|
require.NoError(t, err)
|
|
|
|
srv, err := network.NewServer(srvCfg, chain, chain.GetStateSyncModule(), log)
|
|
|
|
require.NoError(t, err)
|
|
|
|
|
|
|
|
t.Cleanup(srv.Shutdown)
|
|
|
|
|
|
|
|
errCh := make(chan error)
|
|
|
|
go func() {
|
|
|
|
for err := range errCh {
|
|
|
|
require.NoError(t, err)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
}()
|
|
|
|
|
|
|
|
srMod := chain.GetStateModule().(*corestate.Module)
|
|
|
|
sr, err := stateroot.New(srvCfg.StateRootCfg, srMod, log, chain, srv.BroadcastExtensible)
|
|
|
|
require.NoError(t, err)
|
|
|
|
srv.AddExtensibleService(sr, stateroot.Category, sr.OnPayload)
|
|
|
|
|
|
|
|
consens, err := consensus.NewService(consensusCfg(chain, walletPath, srv))
|
|
|
|
require.NoError(t, err)
|
|
|
|
srv.AddConsensusService(consens, consens.OnPayload, consens.OnTransaction)
|
|
|
|
|
|
|
|
rpcSrv := rpcsrv.New(chain, cfg.ApplicationConfiguration.RPC, srv, nil, log, errCh)
|
|
|
|
srv.AddService(&rpcSrv)
|
|
|
|
|
|
|
|
initialAddr := rpcSrv.Addresses()[0]
|
|
|
|
|
|
|
|
go srv.Start()
|
|
|
|
|
|
|
|
// wait until RPC server is started
|
|
|
|
startTimeout, cancel := context.WithTimeout(ctx, 5*time.Second)
|
|
|
|
defer cancel()
|
|
|
|
|
|
|
|
ticker := time.NewTicker(time.Millisecond * 100)
|
|
|
|
defer ticker.Stop()
|
|
|
|
|
|
|
|
var actualAddr string
|
|
|
|
for {
|
|
|
|
select {
|
|
|
|
case <-startTimeout.Done():
|
|
|
|
t.Fatalf("Waiting for server start: %v", startTimeout.Err())
|
|
|
|
case <-ticker.C:
|
|
|
|
if actualAddr == "" {
|
|
|
|
newAddr := rpcSrv.Addresses()[0]
|
|
|
|
if initialAddr == newAddr {
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
actualAddr = newAddr
|
|
|
|
t.Logf("RPC server is listening at %s, checking health", actualAddr)
|
|
|
|
}
|
|
|
|
if _, err = http.Get("http://" + actualAddr); err == nil {
|
|
|
|
return actualAddr
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|