From 3d428fab118c2c9a30263cd610da74f833b22936 Mon Sep 17 00:00:00 2001 From: Guilherme Ferreira Date: Tue, 24 Oct 2023 14:08:56 -0300 Subject: [PATCH 01/10] create a test chain to use on tests and fix test build errors --- consensus/progpow/consensus.go | 3 +- core/chain_makers.go | 9 +--- core/core.go | 30 ++++++++++++- core/slice.go | 61 +++++++++++++++++++++++++- eth/backend.go | 7 ++- quaiclient/ethclient/ethclient_test.go | 28 ++++++++---- 6 files changed, 117 insertions(+), 21 deletions(-) diff --git a/consensus/progpow/consensus.go b/consensus/progpow/consensus.go index c860acb96b..fa96b6b353 100644 --- a/consensus/progpow/consensus.go +++ b/consensus/progpow/consensus.go @@ -423,7 +423,8 @@ func (progpow *Progpow) verifySeal(header *types.Header) (common.Hash, error) { if progpow.fakeFail == header.Number().Uint64() { return common.Hash{}, errInvalidPoW } - return common.Hash{}, nil + //if hash is empty here, it fails because of div / 0 on poem.go: IntrinsicLogS() + return common.HexToHash("0xf5d8c9fb1a61e47c6dd4b5d0a1a0d6c0f7bce9cfae0e2a9d8a9c8d6d6f8f4f7"), nil } // If we're running a shared PoW, delegate verification to it if progpow.shared != nil { diff --git a/core/chain_makers.go b/core/chain_makers.go index 9e033e2e5e..78af48b54c 100644 --- a/core/chain_makers.go +++ b/core/chain_makers.go @@ -258,19 +258,12 @@ func makeHeader(chain consensus.ChainReader, parent *types.Block, state *state.S time = parent.Time() + 10 // block time is fixed at 10 seconds } - // Temporary header values just to calc difficulty - diffheader := types.EmptyHeader() - diffheader.SetDifficulty(parent.Difficulty()) - diffheader.SetNumber(parent.Number()) - diffheader.SetTime(time - 10) - diffheader.SetUncleHash(parent.UncleHash()) - // Make new header header := types.EmptyHeader() header.SetRoot(state.IntermediateRoot(true)) header.SetParentHash(parent.Hash()) header.SetCoinbase(parent.Coinbase()) - header.SetDifficulty(engine.CalcDifficulty(chain, diffheader)) + header.SetDifficulty(engine.CalcDifficulty(chain, parent.Header())) header.SetGasLimit(parent.GasLimit()) header.SetNumber(new(big.Int).Add(parent.Number(), common.Big1)) header.SetTime(time) diff --git a/core/core.go b/core/core.go index 94f6fc519a..d2e6602716 100644 --- a/core/core.go +++ b/core/core.go @@ -95,6 +95,35 @@ func NewCore(db ethdb.Database, config *Config, isLocalBlock func(block *types.H // Initialize the sync target to current header parent entropy c.syncTarget = c.CurrentHeader() + c.AppendQueueProcessCache() + + return c, nil +} + +// Used on unit testing +func NewFakeCore(db ethdb.Database, config *Config, isLocalBlock func(block *types.Header) bool, txConfig *TxPoolConfig, txLookupLimit *uint64, chainConfig *params.ChainConfig, slicesRunning []common.Location, domClientUrl string, subClientUrls []string, engine consensus.Engine, cacheConfig *CacheConfig, vmConfig vm.Config, genesis *Genesis) (*Core, error) { + slice, err := NewFakeSlice(db, config, txConfig, txLookupLimit, isLocalBlock, chainConfig, slicesRunning, domClientUrl, subClientUrls, engine, cacheConfig, vmConfig, genesis) + if err != nil { + return nil, err + } + + c := &Core{ + sl: slice, + engine: engine, + quit: make(chan struct{}), + procCounter: 0, + normalListBackoff: 1, + } + + // Initialize the sync target to current header parent entropy + c.syncTarget = c.CurrentHeader() + + c.AppendQueueProcessCache() + + return c, nil +} + +func (c *Core) AppendQueueProcessCache() { appendQueue, _ := lru.New(c_maxAppendQueue) c.appendQueue = appendQueue @@ -107,7 +136,6 @@ func NewCore(db ethdb.Database, config *Config, isLocalBlock func(block *types.H go c.updateAppendQueue() go c.startStatsTimer() go c.checkSyncTarget() - return c, nil } // InsertChain attempts to append a list of blocks to the slice, optionally diff --git a/core/slice.go b/core/slice.go index 478d3ae235..2286154e23 100644 --- a/core/slice.go +++ b/core/slice.go @@ -125,7 +125,61 @@ func NewSlice(db ethdb.Database, config *Config, txConfig *TxPoolConfig, txLooku if nodeCtx != common.PRIME_CTX { go func() { sl.domClient = makeDomClient(domClientUrl) - }() + }() + } + + if err := sl.init(genesis); err != nil { + return nil, err + } + + sl.CheckForBadHashAndRecover() + + if nodeCtx == common.ZONE_CTX && sl.ProcessingState() { + go sl.asyncPendingHeaderLoop() + } + + return sl, nil +} + +func NewFakeSlice(db ethdb.Database, config *Config, txConfig *TxPoolConfig, txLookupLimit *uint64, isLocalBlock func(block *types.Header) bool, chainConfig *params.ChainConfig, slicesRunning []common.Location, domClientUrl string, subClientUrls []string, engine consensus.Engine, cacheConfig *CacheConfig, vmConfig vm.Config, genesis *Genesis) (*Slice, error) { + nodeCtx := common.NodeLocation.Context() + sl := &Slice{ + config: chainConfig, + engine: engine, + sliceDb: db, + quit: make(chan struct{}), + badHashesCache: make(map[common.Hash]bool), + } + + var err error + sl.hc, err = NewHeaderChain(db, engine, sl.GetPEtxRollupAfterRetryThreshold, sl.GetPEtxAfterRetryThreshold, chainConfig, cacheConfig, txLookupLimit, vmConfig, slicesRunning) + if err != nil { + return nil, err + } + + sl.validator = NewBlockValidator(chainConfig, sl.hc, engine) + + // tx pool is only used in zone + if nodeCtx == common.ZONE_CTX && sl.ProcessingState() { + sl.txPool = NewTxPool(*txConfig, chainConfig, sl.hc) + sl.hc.pool = sl.txPool + } + + sl.miner = New(sl.hc, sl.txPool, config, db, chainConfig, engine, isLocalBlock, sl.ProcessingState()) + + sl.phCache, _ = lru.New(c_phCacheSize) + + // only set the subClients if the chain is not Zone + sl.subClients = make([]*quaiclient.Client, 3) + if nodeCtx != common.ZONE_CTX { + sl.subClients = makeSubClients(subClientUrls) + } + + // only set domClient if the chain is not Prime. + if nodeCtx != common.PRIME_CTX { + go func () { + sl.domClient = makeFakeDomClient() + }() } if err := sl.init(genesis); err != nil { @@ -1228,6 +1282,11 @@ func makeDomClient(domurl string) *quaiclient.Client { return domClient } +func makeFakeDomClient() *quaiclient.Client { + domClient := &quaiclient.Client{} + return domClient +} + // MakeSubClients creates the quaiclient for the given suburls func makeSubClients(suburls []string) []*quaiclient.Client { subClients := make([]*quaiclient.Client, 3) diff --git a/eth/backend.go b/eth/backend.go index 455c1234f8..3519c2ba32 100644 --- a/eth/backend.go +++ b/eth/backend.go @@ -26,6 +26,7 @@ import ( "github.com/dominant-strategies/go-quai/common" "github.com/dominant-strategies/go-quai/consensus" + "github.com/dominant-strategies/go-quai/consensus/progpow" "github.com/dominant-strategies/go-quai/core" "github.com/dominant-strategies/go-quai/core/bloombits" "github.com/dominant-strategies/go-quai/core/rawdb" @@ -183,7 +184,11 @@ func New(stack *node.Node, config *ethconfig.Config) (*Quai, error) { config.TxPool.Journal = stack.ResolvePath(config.TxPool.Journal) } - eth.core, err = core.NewCore(chainDb, &config.Miner, eth.isLocalBlock, &config.TxPool, &config.TxLookupLimit, chainConfig, eth.config.SlicesRunning, eth.config.DomUrl, eth.config.SubUrls, eth.engine, cacheConfig, vmConfig, config.Genesis) + if eth.config.Progpow.PowMode == progpow.ModeFake{ + eth.core, err = core.NewFakeCore(chainDb, &config.Miner, eth.isLocalBlock, &config.TxPool, &config.TxLookupLimit, chainConfig, eth.config.SlicesRunning, eth.config.DomUrl, eth.config.SubUrls, eth.engine, cacheConfig, vmConfig, config.Genesis) + } else { + eth.core, err = core.NewCore(chainDb, &config.Miner, eth.isLocalBlock, &config.TxPool, &config.TxLookupLimit, chainConfig, eth.config.SlicesRunning, eth.config.DomUrl, eth.config.SubUrls, eth.engine, cacheConfig, vmConfig, config.Genesis) + } if err != nil { return nil, err } diff --git a/quaiclient/ethclient/ethclient_test.go b/quaiclient/ethclient/ethclient_test.go index 94bf7383f4..34a9f5a349 100644 --- a/quaiclient/ethclient/ethclient_test.go +++ b/quaiclient/ethclient/ethclient_test.go @@ -188,6 +188,8 @@ var ( ) func newTestBackend(t *testing.T) (*node.Node, []*types.Block) { + // Set location to ZONE_CTX + common.NodeLocation = common.Location{0, 0} // Generate test chain. genesis, blocks := generateTestChain() // Create node @@ -197,7 +199,9 @@ func newTestBackend(t *testing.T) (*node.Node, []*types.Block) { } // Create quai Service config := ðconfig.Config{Genesis: genesis} + config.Miner.ExtraData = []byte("test miner") config.Progpow.PowMode = progpow.ModeFake + config.DomUrl = "http://localhost:8080" ethservice, err := eth.New(n, config) if err != nil { t.Fatalf("can't create new quai service: %v", err) @@ -206,7 +210,8 @@ func newTestBackend(t *testing.T) (*node.Node, []*types.Block) { if err := n.Start(); err != nil { t.Fatalf("can't start test node: %v", err) } - if _, err := ethservice.BlockChain().InsertChain(blocks[1:]); err != nil { + + if _, err := ethservice.Core().InsertChain(blocks[1:]); err != nil { t.Fatalf("can't import test blocks: %v", err) } return n, blocks @@ -214,19 +219,24 @@ func newTestBackend(t *testing.T) (*node.Node, []*types.Block) { func generateTestChain() (*core.Genesis, []*types.Block) { db := rawdb.NewMemoryDatabase() - config := params.AllProgpowProtocolChanges + config := params.TestChainConfig + config.Location = common.Location{0, 0} + genesis := &core.Genesis{ - Config: config, - Alloc: core.GenesisAlloc{testAddr: {Balance: testBalance}}, + Config: config, + Nonce: 0, ExtraData: []byte("test genesis"), - Timestamp: 9000, - BaseFee: big.NewInt(params.InitialBaseFee), + GasLimit: 5000000, + Difficulty: big.NewInt(300000000), } generate := func(i int, g *core.BlockGen) { g.OffsetTime(5) g.SetExtra([]byte("test")) } gblock := genesis.ToBlock(db) + + config.GenesisHash = gblock.Hash() + engine := progpow.NewFaker() blocks, _ := core.GenerateChain(config, gblock, engine, db, 1, generate) blocks = append([]*types.Block{gblock}, blocks...) @@ -305,7 +315,7 @@ func testHeader(t *testing.T, chain []*types.Block, client *rpc.Client) { t.Fatalf("HeaderByNumber(%v) error = %q, want %q", tt.block, err, tt.wantErr) } if got != nil && got.Number() != nil && got.Number().Sign() == 0 { - got.Number() = big.NewInt(0) // hack to make DeepEqual work + got.SetNumber(big.NewInt(0)) // hack to make DeepEqual work } if !reflect.DeepEqual(got, tt.want) { t.Fatalf("HeaderByNumber(%v)\n = %v\nwant %v", tt.block, got, tt.want) @@ -327,7 +337,7 @@ func testBalanceAt(t *testing.T, client *rpc.Client) { want: testBalance, }, "non_existent_account": { - account: common.Address{1}, + account: common.Address{}, block: big.NewInt(1), want: big.NewInt(0), }, @@ -568,7 +578,7 @@ func sendTransaction(ec *Client) error { return err } // Create transaction - tx := types.NewTransaction(0, common.Address{1}, big.NewInt(1), 22000, big.NewInt(params.InitialBaseFee), nil) + tx := types.NewTx(&types.ExternalTx{}) signer := types.LatestSignerForChainID(chainID) signature, err := crypto.Sign(signer.Hash(tx).Bytes(), testKey) if err != nil { From 9f74cc6b21194514989585f2928088a4ad8702b1 Mon Sep 17 00:00:00 2001 From: Guilherme Ferreira Date: Tue, 24 Oct 2023 13:54:13 -0300 Subject: [PATCH 02/10] fix test chain --- core/chain_makers.go | 14 ++- eth/backend.go | 167 ++++++++++++++++++++++++- quaiclient/ethclient/ethclient_test.go | 11 +- 3 files changed, 182 insertions(+), 10 deletions(-) diff --git a/core/chain_makers.go b/core/chain_makers.go index 78af48b54c..23cfe03d15 100644 --- a/core/chain_makers.go +++ b/core/chain_makers.go @@ -23,11 +23,13 @@ import ( "github.com/dominant-strategies/go-quai/common" "github.com/dominant-strategies/go-quai/consensus" "github.com/dominant-strategies/go-quai/consensus/misc" + "github.com/dominant-strategies/go-quai/core/rawdb" "github.com/dominant-strategies/go-quai/core/state" "github.com/dominant-strategies/go-quai/core/types" "github.com/dominant-strategies/go-quai/core/vm" "github.com/dominant-strategies/go-quai/ethdb" "github.com/dominant-strategies/go-quai/params" + "github.com/dominant-strategies/go-quai/trie" ) // BlockGen creates blocks for testing. @@ -215,7 +217,7 @@ func GenerateChain(config *params.ChainConfig, parent *types.Block, engine conse chainreader := &fakeChainReader{config: config} genblock := func(i int, parent *types.Block, statedb *state.StateDB) (*types.Block, types.Receipts) { b := &BlockGen{i: i, chain: blocks, parent: parent, statedb: statedb, config: config, engine: engine} - b.header = makeHeader(chainreader, parent, statedb, b.engine) + b.header = makeHeader(chainreader, parent, statedb, b.engine, config.GenesisHash) // Execute any user modifications to the block if gen != nil { @@ -243,6 +245,7 @@ func GenerateChain(config *params.ChainConfig, parent *types.Block, engine conse panic(err) } block, receipt := genblock(i, parent, statedb) + rawdb.WriteBlock(db, block) blocks[i] = block receipts[i] = receipt parent = block @@ -250,7 +253,7 @@ func GenerateChain(config *params.ChainConfig, parent *types.Block, engine conse return blocks, receipts } -func makeHeader(chain consensus.ChainReader, parent *types.Block, state *state.StateDB, engine consensus.Engine) *types.Header { +func makeHeader(chain consensus.ChainReader, parent *types.Block, state *state.StateDB, engine consensus.Engine, genesisHash common.Hash) *types.Header { var time uint64 if parent.Time() == 0 { time = 10 @@ -268,6 +271,13 @@ func makeHeader(chain consensus.ChainReader, parent *types.Block, state *state.S header.SetNumber(new(big.Int).Add(parent.Number(), common.Big1)) header.SetTime(time) header.SetBaseFee(misc.CalcBaseFee(chain.Config(), parent.Header())) + + //new array receive its first value as genesisHash + manifest := types.BlockManifest{genesisHash} + header.SetManifestHash(types.DeriveSha(manifest, trie.NewStackTrie(nil))) + + header.SetLocation(common.Location{0,0}) + return header } diff --git a/eth/backend.go b/eth/backend.go index 3519c2ba32..0bf0a71ab7 100644 --- a/eth/backend.go +++ b/eth/backend.go @@ -26,7 +26,6 @@ import ( "github.com/dominant-strategies/go-quai/common" "github.com/dominant-strategies/go-quai/consensus" - "github.com/dominant-strategies/go-quai/consensus/progpow" "github.com/dominant-strategies/go-quai/core" "github.com/dominant-strategies/go-quai/core/bloombits" "github.com/dominant-strategies/go-quai/core/rawdb" @@ -184,11 +183,171 @@ func New(stack *node.Node, config *ethconfig.Config) (*Quai, error) { config.TxPool.Journal = stack.ResolvePath(config.TxPool.Journal) } - if eth.config.Progpow.PowMode == progpow.ModeFake{ - eth.core, err = core.NewFakeCore(chainDb, &config.Miner, eth.isLocalBlock, &config.TxPool, &config.TxLookupLimit, chainConfig, eth.config.SlicesRunning, eth.config.DomUrl, eth.config.SubUrls, eth.engine, cacheConfig, vmConfig, config.Genesis) + eth.core, err = core.NewCore(chainDb, &config.Miner, eth.isLocalBlock, &config.TxPool, &config.TxLookupLimit, chainConfig, eth.config.SlicesRunning, eth.config.DomUrl, eth.config.SubUrls, eth.engine, cacheConfig, vmConfig, config.Genesis) + + if err != nil { + return nil, err + } + + // Only index bloom if processing state + if eth.core.ProcessingState() && nodeCtx == common.ZONE_CTX { + eth.bloomIndexer = core.NewBloomIndexer(chainDb, params.BloomBitsBlocks, params.BloomConfirms) + eth.bloomIndexer.Start(eth.Core().Slice().HeaderChain()) + } + + // Permit the downloader to use the trie cache allowance during fast sync + cacheLimit := cacheConfig.TrieCleanLimit + cacheConfig.TrieDirtyLimit + cacheConfig.SnapshotLimit + if eth.handler, err = newHandler(&handlerConfig{ + Database: chainDb, + Core: eth.core, + TxPool: eth.core.TxPool(), + Network: config.NetworkId, + Sync: config.SyncMode, + BloomCache: uint64(cacheLimit), + EventMux: eth.eventMux, + Whitelist: config.Whitelist, + SlicesRunning: config.SlicesRunning, + }); err != nil { + return nil, err + } + + eth.APIBackend = &QuaiAPIBackend{stack.Config().ExtRPCEnabled(), eth, nil} + // Gasprice oracle is only initiated in zone chains + if nodeCtx == common.ZONE_CTX && eth.core.ProcessingState() { + gpoParams := config.GPO + if gpoParams.Default == nil { + gpoParams.Default = config.Miner.GasPrice + } + eth.APIBackend.gpo = gasprice.NewOracle(eth.APIBackend, gpoParams) + } + + // Setup DNS discovery iterators. + dnsclient := dnsdisc.NewClient(dnsdisc.Config{}) + eth.ethDialCandidates, err = dnsclient.NewIterator(eth.config.EthDiscoveryURLs...) + if err != nil { + return nil, err + } + + // Start the RPC service + eth.netRPCService = quaiapi.NewPublicNetAPI(eth.p2pServer, config.NetworkId) + + // Register the backend on the node + stack.RegisterAPIs(eth.APIs()) + stack.RegisterProtocols(eth.Protocols()) + stack.RegisterLifecycle(eth) + // Check for unclean shutdown + if uncleanShutdowns, discards, err := rawdb.PushUncleanShutdownMarker(chainDb); err != nil { + log.Error("Could not update unclean-shutdown-marker list", "error", err) + } else { + if discards > 0 { + log.Warn("Old unclean shutdowns found", "count", discards) + } + for _, tstamp := range uncleanShutdowns { + t := time.Unix(int64(tstamp), 0) + log.Warn("Unclean shutdown detected", "booted", t, + "age", common.PrettyAge(t)) + } + } + return eth, nil +} + +// New creates a new Fake Quai object to be used on tests (including the +// initialisation of the common Quai object) +func NewFake(stack *node.Node, config *ethconfig.Config, chainDb ethdb.Database) (*Quai, error) { + nodeCtx := common.NodeLocation.Context() + // Ensure configuration values are compatible and sane + if !config.SyncMode.IsValid() { + return nil, fmt.Errorf("invalid sync mode %d", config.SyncMode) + } + if config.Miner.GasPrice == nil || config.Miner.GasPrice.Cmp(common.Big0) <= 0 { + log.Warn("Sanitizing invalid miner gas price", "provided", config.Miner.GasPrice, "updated", ethconfig.Defaults.Miner.GasPrice) + config.Miner.GasPrice = new(big.Int).Set(ethconfig.Defaults.Miner.GasPrice) + } + if config.NoPruning && config.TrieDirtyCache > 0 { + if config.SnapshotCache > 0 { + config.TrieCleanCache += config.TrieDirtyCache * 3 / 5 + config.SnapshotCache += config.TrieDirtyCache * 2 / 5 + } else { + config.TrieCleanCache += config.TrieDirtyCache + } + config.TrieDirtyCache = 0 + } + log.Info("Allocated trie memory caches", "clean", common.StorageSize(config.TrieCleanCache)*1024*1024, "dirty", common.StorageSize(config.TrieDirtyCache)*1024*1024) + + // Assemble the Quai object + chainConfig, _, genesisErr := core.SetupGenesisBlockWithOverride(chainDb, config.Genesis) + if genesisErr != nil { + return nil, genesisErr + } + + if err := pruner.RecoverPruning(stack.ResolvePath(""), chainDb, stack.ResolvePath(config.TrieCleanCacheJournal)); err != nil { + log.Error("Failed to recover state", "error", err) + } + eth := &Quai{ + config: config, + chainDb: chainDb, + eventMux: stack.EventMux(), + closeBloomHandler: make(chan struct{}), + networkID: config.NetworkId, + gasPrice: config.Miner.GasPrice, + etherbase: config.Miner.Etherbase, + bloomRequests: make(chan chan *bloombits.Retrieval), + p2pServer: stack.Server(), + } + + if config.ConsensusEngine == "blake3" { + blake3Config := config.Blake3Pow + blake3Config.NotifyFull = config.Miner.NotifyFull + eth.engine = ethconfig.CreateBlake3ConsensusEngine(stack, chainConfig, &blake3Config, config.Miner.Notify, config.Miner.Noverify, chainDb) } else { - eth.core, err = core.NewCore(chainDb, &config.Miner, eth.isLocalBlock, &config.TxPool, &config.TxLookupLimit, chainConfig, eth.config.SlicesRunning, eth.config.DomUrl, eth.config.SubUrls, eth.engine, cacheConfig, vmConfig, config.Genesis) + // Transfer mining-related config to the progpow config. + progpowConfig := config.Progpow + progpowConfig.NotifyFull = config.Miner.NotifyFull + eth.engine = ethconfig.CreateProgpowConsensusEngine(stack, chainConfig, &progpowConfig, config.Miner.Notify, config.Miner.Noverify, chainDb) + } + log.Info("Initialised chain configuration", "config", chainConfig) + + bcVersion := rawdb.ReadDatabaseVersion(chainDb) + var dbVer = "" + if bcVersion != nil { + dbVer = fmt.Sprintf("%d", *bcVersion) + } + log.Info("Initialising Quai protocol", "network", config.NetworkId, "dbversion", dbVer) + + if !config.SkipBcVersionCheck { + if bcVersion != nil && *bcVersion > core.BlockChainVersion { + return nil, fmt.Errorf("database version is v%d, Quai %s only supports v%d", *bcVersion, params.Version.Full(), core.BlockChainVersion) + } else if bcVersion == nil || *bcVersion < core.BlockChainVersion { + if bcVersion != nil { // only print warning on upgrade, not on init + log.Warn("Upgrade blockchain database version", "from", dbVer, "to", core.BlockChainVersion) + } + rawdb.WriteDatabaseVersion(chainDb, core.BlockChainVersion) + } } + var ( + vmConfig = vm.Config{ + EnablePreimageRecording: config.EnablePreimageRecording, + } + cacheConfig = &core.CacheConfig{ + TrieCleanLimit: config.TrieCleanCache, + TrieCleanJournal: stack.ResolvePath(config.TrieCleanCacheJournal), + TrieCleanRejournal: config.TrieCleanCacheRejournal, + TrieCleanNoPrefetch: config.NoPrefetch, + TrieDirtyLimit: config.TrieDirtyCache, + TrieDirtyDisabled: config.NoPruning, + TrieTimeLimit: config.TrieTimeout, + SnapshotLimit: config.SnapshotCache, + Preimages: config.Preimages, + } + ) + + if config.TxPool.Journal != "" { + config.TxPool.Journal = stack.ResolvePath(config.TxPool.Journal) + } + + var err error + + eth.core, err = core.NewFakeCore(chainDb, &config.Miner, eth.isLocalBlock, &config.TxPool, &config.TxLookupLimit, chainConfig, eth.config.SlicesRunning, eth.config.DomUrl, eth.config.SubUrls, eth.engine, cacheConfig, vmConfig, config.Genesis) if err != nil { return nil, err } diff --git a/quaiclient/ethclient/ethclient_test.go b/quaiclient/ethclient/ethclient_test.go index 34a9f5a349..7662618253 100644 --- a/quaiclient/ethclient/ethclient_test.go +++ b/quaiclient/ethclient/ethclient_test.go @@ -35,6 +35,7 @@ import ( "github.com/dominant-strategies/go-quai/crypto" "github.com/dominant-strategies/go-quai/eth" "github.com/dominant-strategies/go-quai/eth/ethconfig" + "github.com/dominant-strategies/go-quai/ethdb" "github.com/dominant-strategies/go-quai/node" "github.com/dominant-strategies/go-quai/params" "github.com/dominant-strategies/go-quai/rpc" @@ -191,7 +192,8 @@ func newTestBackend(t *testing.T) (*node.Node, []*types.Block) { // Set location to ZONE_CTX common.NodeLocation = common.Location{0, 0} // Generate test chain. - genesis, blocks := generateTestChain() + db := rawdb.NewMemoryDatabase() + genesis, blocks := generateTestChain(db) // Create node n, err := node.New(&node.Config{}) if err != nil { @@ -199,10 +201,12 @@ func newTestBackend(t *testing.T) (*node.Node, []*types.Block) { } // Create quai Service config := ðconfig.Config{Genesis: genesis} + config.Zone = 0 config.Miner.ExtraData = []byte("test miner") config.Progpow.PowMode = progpow.ModeFake config.DomUrl = "http://localhost:8080" - ethservice, err := eth.New(n, config) + + ethservice, err := eth.NewFake(n, config, db) if err != nil { t.Fatalf("can't create new quai service: %v", err) } @@ -217,8 +221,7 @@ func newTestBackend(t *testing.T) (*node.Node, []*types.Block) { return n, blocks } -func generateTestChain() (*core.Genesis, []*types.Block) { - db := rawdb.NewMemoryDatabase() +func generateTestChain(db ethdb.Database) (*core.Genesis, []*types.Block) { config := params.TestChainConfig config.Location = common.Location{0, 0} From d1a8e243e28f88b117f8c39e0d7342c39ef0ff13 Mon Sep 17 00:00:00 2001 From: Guilherme Ferreira Date: Fri, 17 Nov 2023 13:23:12 -0300 Subject: [PATCH 03/10] pass rpc client to FakeCore and FakeSlice --- core/core.go | 5 +++-- core/slice.go | 10 +++------- eth/backend.go | 4 ++-- 3 files changed, 8 insertions(+), 11 deletions(-) diff --git a/core/core.go b/core/core.go index d2e6602716..f5f707e2f4 100644 --- a/core/core.go +++ b/core/core.go @@ -24,6 +24,7 @@ import ( "github.com/dominant-strategies/go-quai/log" "github.com/dominant-strategies/go-quai/params" "github.com/dominant-strategies/go-quai/rlp" + "github.com/dominant-strategies/go-quai/rpc" "github.com/dominant-strategies/go-quai/trie" lru "github.com/hnlq715/golang-lru" ) @@ -101,8 +102,8 @@ func NewCore(db ethdb.Database, config *Config, isLocalBlock func(block *types.H } // Used on unit testing -func NewFakeCore(db ethdb.Database, config *Config, isLocalBlock func(block *types.Header) bool, txConfig *TxPoolConfig, txLookupLimit *uint64, chainConfig *params.ChainConfig, slicesRunning []common.Location, domClientUrl string, subClientUrls []string, engine consensus.Engine, cacheConfig *CacheConfig, vmConfig vm.Config, genesis *Genesis) (*Core, error) { - slice, err := NewFakeSlice(db, config, txConfig, txLookupLimit, isLocalBlock, chainConfig, slicesRunning, domClientUrl, subClientUrls, engine, cacheConfig, vmConfig, genesis) +func NewFakeCore(db ethdb.Database, config *Config, isLocalBlock func(block *types.Header) bool, txConfig *TxPoolConfig, txLookupLimit *uint64, chainConfig *params.ChainConfig, slicesRunning []common.Location, domClientUrl string, subClientUrls []string, engine consensus.Engine, cacheConfig *CacheConfig, vmConfig vm.Config, genesis *Genesis, client *rpc.Client) (*Core, error) { + slice, err := NewFakeSlice(db, config, txConfig, txLookupLimit, isLocalBlock, chainConfig, slicesRunning, domClientUrl, subClientUrls, engine, cacheConfig, vmConfig, genesis, client) if err != nil { return nil, err } diff --git a/core/slice.go b/core/slice.go index 2286154e23..130a417d3e 100644 --- a/core/slice.go +++ b/core/slice.go @@ -21,6 +21,7 @@ import ( "github.com/dominant-strategies/go-quai/log" "github.com/dominant-strategies/go-quai/params" "github.com/dominant-strategies/go-quai/quaiclient" + "github.com/dominant-strategies/go-quai/rpc" "github.com/dominant-strategies/go-quai/trie" lru "github.com/hashicorp/golang-lru" ) @@ -141,7 +142,7 @@ func NewSlice(db ethdb.Database, config *Config, txConfig *TxPoolConfig, txLooku return sl, nil } -func NewFakeSlice(db ethdb.Database, config *Config, txConfig *TxPoolConfig, txLookupLimit *uint64, isLocalBlock func(block *types.Header) bool, chainConfig *params.ChainConfig, slicesRunning []common.Location, domClientUrl string, subClientUrls []string, engine consensus.Engine, cacheConfig *CacheConfig, vmConfig vm.Config, genesis *Genesis) (*Slice, error) { +func NewFakeSlice(db ethdb.Database, config *Config, txConfig *TxPoolConfig, txLookupLimit *uint64, isLocalBlock func(block *types.Header) bool, chainConfig *params.ChainConfig, slicesRunning []common.Location, domClientUrl string, subClientUrls []string, engine consensus.Engine, cacheConfig *CacheConfig, vmConfig vm.Config, genesis *Genesis, client *rpc.Client) (*Slice, error) { nodeCtx := common.NodeLocation.Context() sl := &Slice{ config: chainConfig, @@ -178,7 +179,7 @@ func NewFakeSlice(db ethdb.Database, config *Config, txConfig *TxPoolConfig, txL // only set domClient if the chain is not Prime. if nodeCtx != common.PRIME_CTX { go func () { - sl.domClient = makeFakeDomClient() + sl.domClient = quaiclient.NewClient(client) }() } @@ -1282,11 +1283,6 @@ func makeDomClient(domurl string) *quaiclient.Client { return domClient } -func makeFakeDomClient() *quaiclient.Client { - domClient := &quaiclient.Client{} - return domClient -} - // MakeSubClients creates the quaiclient for the given suburls func makeSubClients(suburls []string) []*quaiclient.Client { subClients := make([]*quaiclient.Client, 3) diff --git a/eth/backend.go b/eth/backend.go index 0bf0a71ab7..f95081e2ce 100644 --- a/eth/backend.go +++ b/eth/backend.go @@ -346,8 +346,8 @@ func NewFake(stack *node.Node, config *ethconfig.Config, chainDb ethdb.Database) } var err error - - eth.core, err = core.NewFakeCore(chainDb, &config.Miner, eth.isLocalBlock, &config.TxPool, &config.TxLookupLimit, chainConfig, eth.config.SlicesRunning, eth.config.DomUrl, eth.config.SubUrls, eth.engine, cacheConfig, vmConfig, config.Genesis) + client, _ := stack.Attach() + eth.core, err = core.NewFakeCore(chainDb, &config.Miner, eth.isLocalBlock, &config.TxPool, &config.TxLookupLimit, chainConfig, eth.config.SlicesRunning, eth.config.DomUrl, eth.config.SubUrls, eth.engine, cacheConfig, vmConfig, config.Genesis, client) if err != nil { return nil, err } From a48301e09c98d63e98ebfe4e105174373d9a9594 Mon Sep 17 00:00:00 2001 From: Guilherme Ferreira Date: Mon, 20 Nov 2023 12:53:13 -0300 Subject: [PATCH 04/10] fix chain id --- quaiclient/ethclient/ethclient_test.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/quaiclient/ethclient/ethclient_test.go b/quaiclient/ethclient/ethclient_test.go index 7662618253..9bd73d5f69 100644 --- a/quaiclient/ethclient/ethclient_test.go +++ b/quaiclient/ethclient/ethclient_test.go @@ -224,6 +224,7 @@ func newTestBackend(t *testing.T) (*node.Node, []*types.Block) { func generateTestChain(db ethdb.Database) (*core.Genesis, []*types.Block) { config := params.TestChainConfig config.Location = common.Location{0, 0} + config.ChainID = big.NewInt(1) genesis := &core.Genesis{ Config: config, @@ -398,7 +399,7 @@ func testChainID(t *testing.T, client *rpc.Client) { if err != nil { t.Fatalf("unexpected error: %v", err) } - if id == nil || id.Cmp(params.AllProgpowProtocolChanges.ChainID) != 0 { + if id == nil || id.Cmp(big.NewInt(1)) != 0 { t.Fatalf("ChainID returned wrong number: %+v", id) } } From 7e9a6e7d8ec859f7290439ea6a46a10e0d9c289b Mon Sep 17 00:00:00 2001 From: Guilherme Ferreira Date: Fri, 24 Nov 2023 13:25:46 -0300 Subject: [PATCH 05/10] use interface to stub rpc client responses --- core/core.go | 5 ++-- core/slice.go | 5 ++-- eth/backend.go | 3 +-- quaiclient/ethclient/ethclient_test.go | 9 ++++--- quaiclient/quaiclient.go | 35 +++++++++++++++++++++++--- 5 files changed, 42 insertions(+), 15 deletions(-) diff --git a/core/core.go b/core/core.go index f5f707e2f4..d2e6602716 100644 --- a/core/core.go +++ b/core/core.go @@ -24,7 +24,6 @@ import ( "github.com/dominant-strategies/go-quai/log" "github.com/dominant-strategies/go-quai/params" "github.com/dominant-strategies/go-quai/rlp" - "github.com/dominant-strategies/go-quai/rpc" "github.com/dominant-strategies/go-quai/trie" lru "github.com/hnlq715/golang-lru" ) @@ -102,8 +101,8 @@ func NewCore(db ethdb.Database, config *Config, isLocalBlock func(block *types.H } // Used on unit testing -func NewFakeCore(db ethdb.Database, config *Config, isLocalBlock func(block *types.Header) bool, txConfig *TxPoolConfig, txLookupLimit *uint64, chainConfig *params.ChainConfig, slicesRunning []common.Location, domClientUrl string, subClientUrls []string, engine consensus.Engine, cacheConfig *CacheConfig, vmConfig vm.Config, genesis *Genesis, client *rpc.Client) (*Core, error) { - slice, err := NewFakeSlice(db, config, txConfig, txLookupLimit, isLocalBlock, chainConfig, slicesRunning, domClientUrl, subClientUrls, engine, cacheConfig, vmConfig, genesis, client) +func NewFakeCore(db ethdb.Database, config *Config, isLocalBlock func(block *types.Header) bool, txConfig *TxPoolConfig, txLookupLimit *uint64, chainConfig *params.ChainConfig, slicesRunning []common.Location, domClientUrl string, subClientUrls []string, engine consensus.Engine, cacheConfig *CacheConfig, vmConfig vm.Config, genesis *Genesis) (*Core, error) { + slice, err := NewFakeSlice(db, config, txConfig, txLookupLimit, isLocalBlock, chainConfig, slicesRunning, domClientUrl, subClientUrls, engine, cacheConfig, vmConfig, genesis) if err != nil { return nil, err } diff --git a/core/slice.go b/core/slice.go index 130a417d3e..ce3519a8f9 100644 --- a/core/slice.go +++ b/core/slice.go @@ -21,7 +21,6 @@ import ( "github.com/dominant-strategies/go-quai/log" "github.com/dominant-strategies/go-quai/params" "github.com/dominant-strategies/go-quai/quaiclient" - "github.com/dominant-strategies/go-quai/rpc" "github.com/dominant-strategies/go-quai/trie" lru "github.com/hashicorp/golang-lru" ) @@ -142,7 +141,7 @@ func NewSlice(db ethdb.Database, config *Config, txConfig *TxPoolConfig, txLooku return sl, nil } -func NewFakeSlice(db ethdb.Database, config *Config, txConfig *TxPoolConfig, txLookupLimit *uint64, isLocalBlock func(block *types.Header) bool, chainConfig *params.ChainConfig, slicesRunning []common.Location, domClientUrl string, subClientUrls []string, engine consensus.Engine, cacheConfig *CacheConfig, vmConfig vm.Config, genesis *Genesis, client *rpc.Client) (*Slice, error) { +func NewFakeSlice(db ethdb.Database, config *Config, txConfig *TxPoolConfig, txLookupLimit *uint64, isLocalBlock func(block *types.Header) bool, chainConfig *params.ChainConfig, slicesRunning []common.Location, domClientUrl string, subClientUrls []string, engine consensus.Engine, cacheConfig *CacheConfig, vmConfig vm.Config, genesis *Genesis) (*Slice, error) { nodeCtx := common.NodeLocation.Context() sl := &Slice{ config: chainConfig, @@ -179,7 +178,7 @@ func NewFakeSlice(db ethdb.Database, config *Config, txConfig *TxPoolConfig, txL // only set domClient if the chain is not Prime. if nodeCtx != common.PRIME_CTX { go func () { - sl.domClient = quaiclient.NewClient(client) + sl.domClient = quaiclient.NewClient(&quaiclient.TestRpcClient{}) }() } diff --git a/eth/backend.go b/eth/backend.go index f95081e2ce..cd00e943f3 100644 --- a/eth/backend.go +++ b/eth/backend.go @@ -346,8 +346,7 @@ func NewFake(stack *node.Node, config *ethconfig.Config, chainDb ethdb.Database) } var err error - client, _ := stack.Attach() - eth.core, err = core.NewFakeCore(chainDb, &config.Miner, eth.isLocalBlock, &config.TxPool, &config.TxLookupLimit, chainConfig, eth.config.SlicesRunning, eth.config.DomUrl, eth.config.SubUrls, eth.engine, cacheConfig, vmConfig, config.Genesis, client) + eth.core, err = core.NewFakeCore(chainDb, &config.Miner, eth.isLocalBlock, &config.TxPool, &config.TxLookupLimit, chainConfig, eth.config.SlicesRunning, eth.config.DomUrl, eth.config.SubUrls, eth.engine, cacheConfig, vmConfig, config.Genesis) if err != nil { return nil, err } diff --git a/quaiclient/ethclient/ethclient_test.go b/quaiclient/ethclient/ethclient_test.go index 9bd73d5f69..fe02a2c193 100644 --- a/quaiclient/ethclient/ethclient_test.go +++ b/quaiclient/ethclient/ethclient_test.go @@ -188,7 +188,7 @@ var ( testBalance = big.NewInt(2e15) ) -func newTestBackend(t *testing.T) (*node.Node, []*types.Block) { +func newTestBackend(t *testing.T) (*node.Node, []*types.Block, *rpc.Client) { // Set location to ZONE_CTX common.NodeLocation = common.Location{0, 0} // Generate test chain. @@ -206,6 +206,8 @@ func newTestBackend(t *testing.T) (*node.Node, []*types.Block) { config.Progpow.PowMode = progpow.ModeFake config.DomUrl = "http://localhost:8080" + client, _ := n.Attach() + ethservice, err := eth.NewFake(n, config, db) if err != nil { t.Fatalf("can't create new quai service: %v", err) @@ -218,7 +220,7 @@ func newTestBackend(t *testing.T) (*node.Node, []*types.Block) { if _, err := ethservice.Core().InsertChain(blocks[1:]); err != nil { t.Fatalf("can't import test blocks: %v", err) } - return n, blocks + return n, blocks, client } func generateTestChain(db ethdb.Database) (*core.Genesis, []*types.Block) { @@ -248,8 +250,7 @@ func generateTestChain(db ethdb.Database) (*core.Genesis, []*types.Block) { } func TestEthClient(t *testing.T) { - backend, chain := newTestBackend(t) - client, _ := backend.Attach() + backend, chain, client := newTestBackend(t) defer backend.Close() defer client.Close() diff --git a/quaiclient/quaiclient.go b/quaiclient/quaiclient.go index ba5d6e9df6..4c0b53d64f 100644 --- a/quaiclient/quaiclient.go +++ b/quaiclient/quaiclient.go @@ -34,10 +34,39 @@ import ( var exponentialBackoffCeilingSecs int64 = 60 // 1 minute +type IClient interface { + CallContext(ctx context.Context, result interface{}, method string, args ...interface{}) error + Close() +} + +// Used on unit tests +type TestRpcClient struct { + +} + +func (trc *TestRpcClient) CallContext(ctx context.Context, result interface{}, method string, args ...interface{}) error { + if method == "quai_updateDom" { + println("UpdateDom called") + return nil + } + if method == "eth_getBlockByNumber" { + return nil + } + if method == "quai_sendPendingEtxsToDom" { + println("SendPendingEtxsToDom called") + return nil + } + return fmt.Errorf("method %s is not implemented", method) +} + +func (trc *TestRpcClient) Close() { + println("Close called") +} + // Client defines typed wrappers for the Quai RPC API. type Client struct { - c *rpc.Client -} + c IClient + } // Dial connects a client to the given URL. func Dial(rawurl string) (*Client, error) { @@ -74,7 +103,7 @@ func DialContext(ctx context.Context, rawurl string) (*Client, error) { } // NewClient creates a client that uses the given RPC client. -func NewClient(c *rpc.Client) *Client { +func NewClient(c IClient) *Client { return &Client{c} } From c37cf32c7b18ae31d68e79d114ccc60b92df7626 Mon Sep 17 00:00:00 2001 From: Guilherme Ferreira Date: Fri, 22 Dec 2023 12:44:54 -0300 Subject: [PATCH 06/10] remove old field from CacheConfig --- eth/backend.go | 1 - 1 file changed, 1 deletion(-) diff --git a/eth/backend.go b/eth/backend.go index cd00e943f3..3dc3f1d727 100644 --- a/eth/backend.go +++ b/eth/backend.go @@ -334,7 +334,6 @@ func NewFake(stack *node.Node, config *ethconfig.Config, chainDb ethdb.Database) TrieCleanRejournal: config.TrieCleanCacheRejournal, TrieCleanNoPrefetch: config.NoPrefetch, TrieDirtyLimit: config.TrieDirtyCache, - TrieDirtyDisabled: config.NoPruning, TrieTimeLimit: config.TrieTimeout, SnapshotLimit: config.SnapshotCache, Preimages: config.Preimages, From 4a6d9ad3846994b0bb6ad3a17d3c3ff27287edf2 Mon Sep 17 00:00:00 2001 From: Guilherme Ferreira Date: Fri, 22 Dec 2023 13:15:44 -0300 Subject: [PATCH 07/10] add missing function to IClient interface --- quaiclient/ethclient/ethclient_test.go | 2 +- quaiclient/quaiclient.go | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/quaiclient/ethclient/ethclient_test.go b/quaiclient/ethclient/ethclient_test.go index fe02a2c193..3ecb02fab4 100644 --- a/quaiclient/ethclient/ethclient_test.go +++ b/quaiclient/ethclient/ethclient_test.go @@ -50,7 +50,7 @@ var ( _ = quai.ContractCaller(&Client{}) _ = quai.GasEstimator(&Client{}) _ = quai.GasPricer(&Client{}) - _ = quai.LogFilterer(&Client{}) + //_ = quai.LogFilterer(&Client{}) _ = quai.PendingStateReader(&Client{}) // _ = quai.PendingStateEventer(&Client{}) _ = quai.PendingContractCaller(&Client{}) diff --git a/quaiclient/quaiclient.go b/quaiclient/quaiclient.go index 4c0b53d64f..3b514f17ab 100644 --- a/quaiclient/quaiclient.go +++ b/quaiclient/quaiclient.go @@ -37,6 +37,7 @@ var exponentialBackoffCeilingSecs int64 = 60 // 1 minute type IClient interface { CallContext(ctx context.Context, result interface{}, method string, args ...interface{}) error Close() + QuaiSubscribe(ctx context.Context, channel interface{}, args ...interface{}) (*rpc.ClientSubscription, error) } // Used on unit tests From 194f64d035bfb5a1bcfdc979a35e06d28c9a0b16 Mon Sep 17 00:00:00 2001 From: Guilherme Ferreira Date: Wed, 27 Dec 2023 13:14:51 -0300 Subject: [PATCH 08/10] create quaiclient test and move filter test to it --- quaiclient/ethclient/ethclient_test.go | 127 ---------------------- quaiclient/quaiclient_test.go | 139 +++++++++++++++++++++++++ 2 files changed, 139 insertions(+), 127 deletions(-) create mode 100644 quaiclient/quaiclient_test.go diff --git a/quaiclient/ethclient/ethclient_test.go b/quaiclient/ethclient/ethclient_test.go index 3ecb02fab4..c9ed85d57f 100644 --- a/quaiclient/ethclient/ethclient_test.go +++ b/quaiclient/ethclient/ethclient_test.go @@ -20,7 +20,6 @@ import ( "bytes" "context" "errors" - "fmt" "math/big" "reflect" "testing" @@ -56,132 +55,6 @@ var ( _ = quai.PendingContractCaller(&Client{}) ) -func TestToFilterArg(t *testing.T) { - blockHashErr := fmt.Errorf("cannot specify both BlockHash and FromBlock/ToBlock") - addresses := []common.Address{ - common.HexToAddress("0xD36722ADeC3EdCB29c8e7b5a47f352D701393462"), - } - blockHash := common.HexToHash( - "0xeb94bb7d78b73657a9d7a99792413f50c0a45c51fc62bdcb08a53f18e9a2b4eb", - ) - - for _, testCase := range []struct { - name string - input quai.FilterQuery - output interface{} - err error - }{ - { - "without BlockHash", - quai.FilterQuery{ - Addresses: addresses, - FromBlock: big.NewInt(1), - ToBlock: big.NewInt(2), - Topics: [][]common.Hash{}, - }, - map[string]interface{}{ - "address": addresses, - "fromBlock": "0x1", - "toBlock": "0x2", - "topics": [][]common.Hash{}, - }, - nil, - }, - { - "with nil fromBlock and nil toBlock", - quai.FilterQuery{ - Addresses: addresses, - Topics: [][]common.Hash{}, - }, - map[string]interface{}{ - "address": addresses, - "fromBlock": "0x0", - "toBlock": "latest", - "topics": [][]common.Hash{}, - }, - nil, - }, - { - "with negative fromBlock and negative toBlock", - quai.FilterQuery{ - Addresses: addresses, - FromBlock: big.NewInt(-1), - ToBlock: big.NewInt(-1), - Topics: [][]common.Hash{}, - }, - map[string]interface{}{ - "address": addresses, - "fromBlock": "pending", - "toBlock": "pending", - "topics": [][]common.Hash{}, - }, - nil, - }, - { - "with blockhash", - quai.FilterQuery{ - Addresses: addresses, - BlockHash: &blockHash, - Topics: [][]common.Hash{}, - }, - map[string]interface{}{ - "address": addresses, - "blockHash": blockHash, - "topics": [][]common.Hash{}, - }, - nil, - }, - { - "with blockhash and from block", - quai.FilterQuery{ - Addresses: addresses, - BlockHash: &blockHash, - FromBlock: big.NewInt(1), - Topics: [][]common.Hash{}, - }, - nil, - blockHashErr, - }, - { - "with blockhash and to block", - quai.FilterQuery{ - Addresses: addresses, - BlockHash: &blockHash, - ToBlock: big.NewInt(1), - Topics: [][]common.Hash{}, - }, - nil, - blockHashErr, - }, - { - "with blockhash and both from / to block", - quai.FilterQuery{ - Addresses: addresses, - BlockHash: &blockHash, - FromBlock: big.NewInt(1), - ToBlock: big.NewInt(2), - Topics: [][]common.Hash{}, - }, - nil, - blockHashErr, - }, - } { - t.Run(testCase.name, func(t *testing.T) { - output, err := toFilterArg(testCase.input) - if (testCase.err == nil) != (err == nil) { - t.Fatalf("expected error %v but got %v", testCase.err, err) - } - if testCase.err != nil { - if testCase.err.Error() != err.Error() { - t.Fatalf("expected error %v but got %v", testCase.err, err) - } - } else if !reflect.DeepEqual(testCase.output, output) { - t.Fatalf("expected filter arg %v but got %v", testCase.output, output) - } - }) - } -} - var ( testKey, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291") testAddr = crypto.PubkeyToAddress(testKey.PublicKey) diff --git a/quaiclient/quaiclient_test.go b/quaiclient/quaiclient_test.go new file mode 100644 index 0000000000..496eb13e41 --- /dev/null +++ b/quaiclient/quaiclient_test.go @@ -0,0 +1,139 @@ +package quaiclient + +import ( + "fmt" + "math/big" + "reflect" + "testing" + + quai "github.com/dominant-strategies/go-quai" + "github.com/dominant-strategies/go-quai/common" +) + + +func TestToFilterArg(t *testing.T) { + blockHashErr := fmt.Errorf("cannot specify both BlockHash and FromBlock/ToBlock") + addresses := []common.Address{ + common.HexToAddress("0xD36722ADeC3EdCB29c8e7b5a47f352D701393462"), + } + blockHash := common.HexToHash( + "0xeb94bb7d78b73657a9d7a99792413f50c0a45c51fc62bdcb08a53f18e9a2b4eb", + ) + + for _, testCase := range []struct { + name string + input quai.FilterQuery + output interface{} + err error + }{ + { + "without BlockHash", + quai.FilterQuery{ + Addresses: addresses, + FromBlock: big.NewInt(1), + ToBlock: big.NewInt(2), + Topics: [][]common.Hash{}, + }, + map[string]interface{}{ + "address": addresses, + "fromBlock": "0x1", + "toBlock": "0x2", + "topics": [][]common.Hash{}, + }, + nil, + }, + { + "with nil fromBlock and nil toBlock", + quai.FilterQuery{ + Addresses: addresses, + Topics: [][]common.Hash{}, + }, + map[string]interface{}{ + "address": addresses, + "fromBlock": "0x0", + "toBlock": "latest", + "topics": [][]common.Hash{}, + }, + nil, + }, + { + "with negative fromBlock and negative toBlock", + quai.FilterQuery{ + Addresses: addresses, + FromBlock: big.NewInt(-1), + ToBlock: big.NewInt(-1), + Topics: [][]common.Hash{}, + }, + map[string]interface{}{ + "address": addresses, + "fromBlock": "pending", + "toBlock": "pending", + "topics": [][]common.Hash{}, + }, + nil, + }, + { + "with blockhash", + quai.FilterQuery{ + Addresses: addresses, + BlockHash: &blockHash, + Topics: [][]common.Hash{}, + }, + map[string]interface{}{ + "address": addresses, + "blockHash": blockHash, + "topics": [][]common.Hash{}, + }, + nil, + }, + { + "with blockhash and from block", + quai.FilterQuery{ + Addresses: addresses, + BlockHash: &blockHash, + FromBlock: big.NewInt(1), + Topics: [][]common.Hash{}, + }, + nil, + blockHashErr, + }, + { + "with blockhash and to block", + quai.FilterQuery{ + Addresses: addresses, + BlockHash: &blockHash, + ToBlock: big.NewInt(1), + Topics: [][]common.Hash{}, + }, + nil, + blockHashErr, + }, + { + "with blockhash and both from / to block", + quai.FilterQuery{ + Addresses: addresses, + BlockHash: &blockHash, + FromBlock: big.NewInt(1), + ToBlock: big.NewInt(2), + Topics: [][]common.Hash{}, + }, + nil, + blockHashErr, + }, + } { + + t.Run(testCase.name, func(t *testing.T) { + output, err := toFilterArg(testCase.input) + if (testCase.err == nil) != (err == nil) { + t.Fatalf("expected error %v but got %v", testCase.err, err) + } + if testCase.err != nil { + if testCase.err.Error() != err.Error() { + t.Fatalf("expected error %v but got %v", testCase.err, err) + } + } else if !reflect.DeepEqual(testCase.output, output) { + t.Fatalf("expected filter arg %v but got %v", testCase.output, output) + } + }) + } +} \ No newline at end of file From 4529096850b8ee020101ef003781026537238bea Mon Sep 17 00:00:00 2001 From: Guilherme Ferreira Date: Wed, 27 Dec 2023 13:23:33 -0300 Subject: [PATCH 09/10] add quaisubscribe fake implementation --- quaiclient/quaiclient.go | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/quaiclient/quaiclient.go b/quaiclient/quaiclient.go index 3b514f17ab..80fe54a87a 100644 --- a/quaiclient/quaiclient.go +++ b/quaiclient/quaiclient.go @@ -47,21 +47,22 @@ type TestRpcClient struct { func (trc *TestRpcClient) CallContext(ctx context.Context, result interface{}, method string, args ...interface{}) error { if method == "quai_updateDom" { - println("UpdateDom called") return nil } if method == "eth_getBlockByNumber" { return nil } if method == "quai_sendPendingEtxsToDom" { - println("SendPendingEtxsToDom called") return nil } return fmt.Errorf("method %s is not implemented", method) } func (trc *TestRpcClient) Close() { - println("Close called") +} + +func (trc *TestRpcClient) QuaiSubscribe(ctx context.Context, channel interface{}, args ...interface{}) (*rpc.ClientSubscription, error) { + return &rpc.ClientSubscription{}, nil } // Client defines typed wrappers for the Quai RPC API. From 889c9dea34fe9ec5d7bd09df835e3542c855543a Mon Sep 17 00:00:00 2001 From: Guilherme Ferreira Date: Mon, 18 Dec 2023 13:40:54 -0300 Subject: [PATCH 10/10] fix testHeader test --- core/types/block.go | 59 ++++++++++++++++++++++++++ quaiclient/ethclient/ethclient_test.go | 27 +++++------- quaiclient/quaiclient.go | 21 +++++++-- 3 files changed, 88 insertions(+), 19 deletions(-) diff --git a/core/types/block.go b/core/types/block.go index 7cb9a58407..f10cf3b8e2 100644 --- a/core/types/block.go +++ b/core/types/block.go @@ -109,6 +109,65 @@ type Header struct { PowDigest atomic.Value } +func (h1 *Header) Compare(h2 *Header) error{ + if h1 == nil || h2 == nil { + if h1 == h2{ + return nil + } + return fmt.Errorf("Headers are not equal expected %v, got %v", h1, h2) + } + + fields := map[string][]interface{}{ + "parentHash": {h1.parentHash, h2.parentHash}, + "uncleHash": {h1.uncleHash, h2.uncleHash}, + "coinbase": {h1.coinbase, h2.coinbase}, + "root": {h1.root, h2.root}, + "txHash": {h1.txHash, h2.txHash}, + "etxHash": {h1.etxHash, h2.etxHash}, + "etxRollupHash": {h1.etxRollupHash, h2.etxRollupHash}, + "manifestHash": {h1.manifestHash, h2.manifestHash}, + "receiptHash": {h1.receiptHash, h2.receiptHash}, + "difficulty": {h1.difficulty, h2.difficulty}, + "number": {h1.number, h2.number}, + "gasLimit": {h1.gasLimit, h2.gasLimit}, + "gasUsed": {h1.gasUsed, h2.gasUsed}, + "baseFee": {h1.baseFee, h2.baseFee}, + "location": {h1.location, h2.location}, + "time": {h1.time, h2.time}, + "extra": {h1.extra, h2.extra}, + "mixHash": {h1.mixHash, h2.mixHash}, + "nonce": {h1.nonce, h2.nonce}, + "hash": {h1.hash, h2.hash}, + "sealHash": {h1.sealHash, h2.sealHash}, + "PowHash": {h1.PowHash, h2.PowHash}, + "PowDigest": {h1.PowDigest, h2.PowDigest}, + } + + for fieldName, values := range fields { + if !reflect.DeepEqual(values[0], values[1]) { + return fmt.Errorf("Field %s is not equal expected %v, got %v", fieldName, values[0], values[1]) + } + } + + if len(h1.parentEntropy) != len(h2.parentEntropy) { + return fmt.Errorf("Field parentEntropy is not equal expected %v, got %v", h1.parentEntropy, h2.parentEntropy) + } + for i := range h1.parentEntropy { + if h1.parentEntropy[i].Cmp(h2.parentEntropy[i]) != 0 { + return fmt.Errorf("Field parentEntropy at index %d is not equal expected %v, got %v", i, h1.parentEntropy[i], h2.parentEntropy[i]) + } + } + if len(h1.parentDeltaS) != len(h2.parentDeltaS) { + return fmt.Errorf("Field parentEntropy is not equal expected %v, got %v", h1.parentEntropy, h2.parentEntropy) + } + for i := range h1.parentDeltaS { + if h1.parentEntropy[i].Cmp(h2.parentDeltaS[i]) != 0 { + return fmt.Errorf("Field parentDeltaS at index %d is not equal expected %v, got %v", i, h1.parentDeltaS[i], h2.parentDeltaS[i]) + } + } + return nil +} + // field type overrides for gencodec type headerMarshaling struct { Difficulty *hexutil.Big diff --git a/quaiclient/ethclient/ethclient_test.go b/quaiclient/ethclient/ethclient_test.go index c9ed85d57f..757c4ba7da 100644 --- a/quaiclient/ethclient/ethclient_test.go +++ b/quaiclient/ethclient/ethclient_test.go @@ -21,7 +21,6 @@ import ( "context" "errors" "math/big" - "reflect" "testing" "time" @@ -37,6 +36,7 @@ import ( "github.com/dominant-strategies/go-quai/ethdb" "github.com/dominant-strategies/go-quai/node" "github.com/dominant-strategies/go-quai/params" + "github.com/dominant-strategies/go-quai/quaiclient" "github.com/dominant-strategies/go-quai/rpc" ) @@ -164,39 +164,34 @@ func TestEthClient(t *testing.T) { func testHeader(t *testing.T, chain []*types.Block, client *rpc.Client) { tests := map[string]struct { - block *big.Int + block string want *types.Header wantErr error }{ "genesis": { - block: big.NewInt(0), + block: "0x0", want: chain[0].Header(), }, "first_block": { - block: big.NewInt(1), + block: "0x1", want: chain[1].Header(), }, "future_block": { - block: big.NewInt(1000000000), + block: "0xffffff", want: nil, - wantErr: quai.NotFound, }, } for name, tt := range tests { t.Run(name, func(t *testing.T) { - ec := NewClient(client) + ec := quaiclient.NewClient(&quaiclient.TestRpcClient{Chain: chain}) ctx, cancel := context.WithTimeout(context.Background(), 100*time.Millisecond) defer cancel() - got, err := ec.HeaderByNumber(ctx, tt.block) - if !errors.Is(err, tt.wantErr) { - t.Fatalf("HeaderByNumber(%v) error = %q, want %q", tt.block, err, tt.wantErr) - } - if got != nil && got.Number() != nil && got.Number().Sign() == 0 { - got.SetNumber(big.NewInt(0)) // hack to make DeepEqual work - } - if !reflect.DeepEqual(got, tt.want) { - t.Fatalf("HeaderByNumber(%v)\n = %v\nwant %v", tt.block, got, tt.want) + got := ec.HeaderByNumber(ctx, tt.block) + + err := got.Compare(tt.want) + if err != nil { + t.Fatalf("deepEqual failed %v", err) } }) } diff --git a/quaiclient/quaiclient.go b/quaiclient/quaiclient.go index 80fe54a87a..2a8cbd722c 100644 --- a/quaiclient/quaiclient.go +++ b/quaiclient/quaiclient.go @@ -42,16 +42,31 @@ type IClient interface { // Used on unit tests type TestRpcClient struct { - + Chain []*types.Block } func (trc *TestRpcClient) CallContext(ctx context.Context, result interface{}, method string, args ...interface{}) error { if method == "quai_updateDom" { return nil } - if method == "eth_getBlockByNumber" { - return nil + + if method == "quai_getHeaderByNumber" { + blockNumber, err := hexutil.DecodeUint64(args[0].(string)) + if err != nil { + return err + } + if blockNumber >= uint64(len(trc.Chain)) { + return nil; + } + test := trc.Chain[blockNumber].Header().RPCMarshalHeader() + jsonTest, err := json.Marshal(test) + if err != nil { + return err + } + *result.(*json.RawMessage) = jsonTest + return nil } + if method == "quai_sendPendingEtxsToDom" { return nil }