Merge pull request #11 from deep-stack/pm-integration-testing
Add integration tests
This commit is contained in:
commit
7f079a0d38
@ -7,7 +7,6 @@ import (
|
|||||||
"os/signal"
|
"os/signal"
|
||||||
"sync"
|
"sync"
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum/statediff"
|
|
||||||
log "github.com/sirupsen/logrus"
|
log "github.com/sirupsen/logrus"
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
"github.com/spf13/viper"
|
"github.com/spf13/viper"
|
||||||
@ -34,20 +33,7 @@ func stateValidator() {
|
|||||||
logWithCommand.Fatal(err)
|
logWithCommand.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
height := viper.GetUint64("validate.block-height")
|
service := validator.NewService(cfg, nil)
|
||||||
if height < 1 {
|
|
||||||
logWithCommand.Fatalf("block height cannot be less the 1")
|
|
||||||
}
|
|
||||||
trail := viper.GetUint64("validate.trail")
|
|
||||||
sleepInterval := viper.GetUint("validate.sleepInterval")
|
|
||||||
|
|
||||||
chainConfigPath := viper.GetString("ethereum.chainConfig")
|
|
||||||
chainCfg, err := statediff.LoadConfig(chainConfigPath)
|
|
||||||
if err != nil {
|
|
||||||
logWithCommand.Fatal(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
service := validator.NewService(cfg.DB, height, trail, sleepInterval, chainCfg)
|
|
||||||
|
|
||||||
wg := new(sync.WaitGroup)
|
wg := new(sync.WaitGroup)
|
||||||
wg.Add(1)
|
wg.Add(1)
|
||||||
|
@ -6,6 +6,7 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum/params"
|
"github.com/ethereum/go-ethereum/params"
|
||||||
|
"github.com/ethereum/go-ethereum/statediff"
|
||||||
"github.com/ethereum/go-ethereum/statediff/indexer/database/sql/postgres"
|
"github.com/ethereum/go-ethereum/statediff/indexer/database/sql/postgres"
|
||||||
"github.com/jmoiron/sqlx"
|
"github.com/jmoiron/sqlx"
|
||||||
"github.com/spf13/viper"
|
"github.com/spf13/viper"
|
||||||
@ -59,11 +60,35 @@ var TestChainConfig = ¶ms.ChainConfig{
|
|||||||
type Config struct {
|
type Config struct {
|
||||||
dbConfig postgres.Config
|
dbConfig postgres.Config
|
||||||
DB *sqlx.DB
|
DB *sqlx.DB
|
||||||
|
|
||||||
|
ChainCfg *params.ChainConfig
|
||||||
|
|
||||||
|
BlockNum, Trail uint64
|
||||||
|
SleepInterval uint
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewConfig() (*Config, error) {
|
func NewConfig() (*Config, error) {
|
||||||
cfg := new(Config)
|
cfg := new(Config)
|
||||||
return cfg, cfg.setupDB()
|
err := cfg.setupDB()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
cfg.BlockNum = viper.GetUint64("validate.block-height")
|
||||||
|
if cfg.BlockNum < 1 {
|
||||||
|
return nil, fmt.Errorf("block height cannot be less the 1")
|
||||||
|
}
|
||||||
|
|
||||||
|
cfg.Trail = viper.GetUint64("validate.trail")
|
||||||
|
cfg.SleepInterval = viper.GetUint("validate.sleepInterval")
|
||||||
|
|
||||||
|
chainConfigPath := viper.GetString("ethereum.chainConfig")
|
||||||
|
cfg.ChainCfg, err = statediff.LoadConfig(chainConfigPath)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return cfg, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Config) setupDB() error {
|
func (c *Config) setupDB() error {
|
||||||
|
@ -37,17 +37,19 @@ type service struct {
|
|||||||
logger *log.Logger
|
logger *log.Logger
|
||||||
chainCfg *params.ChainConfig
|
chainCfg *params.ChainConfig
|
||||||
quitChan chan bool
|
quitChan chan bool
|
||||||
|
progressChan chan uint64
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewService(db *sqlx.DB, blockNum, trailNum uint64, sleepInterval uint, chainCfg *params.ChainConfig) *service {
|
func NewService(cfg *Config, progressChan chan uint64) *service {
|
||||||
return &service{
|
return &service{
|
||||||
db: db,
|
db: cfg.DB,
|
||||||
blockNum: blockNum,
|
blockNum: cfg.BlockNum,
|
||||||
trail: trailNum,
|
trail: cfg.Trail,
|
||||||
sleepInterval: sleepInterval,
|
sleepInterval: cfg.SleepInterval,
|
||||||
logger: log.New(),
|
logger: log.New(),
|
||||||
chainCfg: chainCfg,
|
chainCfg: cfg.ChainCfg,
|
||||||
quitChan: make(chan bool),
|
quitChan: make(chan bool),
|
||||||
|
progressChan: progressChan,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -96,7 +98,9 @@ func (s *service) Start(ctx context.Context, wg *sync.WaitGroup) {
|
|||||||
select {
|
select {
|
||||||
case <-s.quitChan:
|
case <-s.quitChan:
|
||||||
s.logger.Infof("last validated block %v", idxBlockNum-1)
|
s.logger.Infof("last validated block %v", idxBlockNum-1)
|
||||||
s.logger.Info("stopping ipld-eth-db-validator process")
|
if s.progressChan != nil {
|
||||||
|
close(s.progressChan)
|
||||||
|
}
|
||||||
return
|
return
|
||||||
default:
|
default:
|
||||||
idxBlockNum, err = s.Validate(ctx, api, idxBlockNum)
|
idxBlockNum, err = s.Validate(ctx, api, idxBlockNum)
|
||||||
@ -111,6 +115,7 @@ func (s *service) Start(ctx context.Context, wg *sync.WaitGroup) {
|
|||||||
|
|
||||||
// Stop is used to gracefully stop the service
|
// Stop is used to gracefully stop the service
|
||||||
func (s *service) Stop() {
|
func (s *service) Stop() {
|
||||||
|
s.logger.Info("stopping ipld-eth-db-validator process")
|
||||||
close(s.quitChan)
|
close(s.quitChan)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -129,6 +134,10 @@ func (s *service) Validate(ctx context.Context, api *ipldEth.PublicEthAPI, idxBl
|
|||||||
}
|
}
|
||||||
|
|
||||||
s.logger.Infof("state root verified for block %d", idxBlockNum)
|
s.logger.Infof("state root verified for block %d", idxBlockNum)
|
||||||
|
if s.progressChan != nil {
|
||||||
|
s.progressChan <- idxBlockNum
|
||||||
|
}
|
||||||
|
|
||||||
idxBlockNum++
|
idxBlockNum++
|
||||||
} else {
|
} else {
|
||||||
// Sleep / wait for head to move ahead
|
// Sleep / wait for head to move ahead
|
||||||
|
@ -6,18 +6,18 @@
|
|||||||
|
|
||||||
- Clone [stack-orchestrator](https://github.com/vulcanize/stack-orchestrator) and [go-ethereum](https://github.com/vulcanize/go-ethereum) repositories.
|
- Clone [stack-orchestrator](https://github.com/vulcanize/stack-orchestrator) and [go-ethereum](https://github.com/vulcanize/go-ethereum) repositories.
|
||||||
|
|
||||||
- Checkout [v3 release](https://github.com/vulcanize/go-ethereum/releases/tag/v1.10.17-statediff-3.2.1) in go-ethereum repo.
|
- Checkout [v3 release](https://github.com/vulcanize/go-ethereum/releases/tag/v1.10.18-statediff-3.2.2) in go-ethereum repo.
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
# In go-ethereum repo.
|
# In go-ethereum repo.
|
||||||
git checkout v1.10.17-statediff-3.2.1
|
git checkout v1.10.18-statediff-3.2.2
|
||||||
```
|
```
|
||||||
|
|
||||||
- Checkout working commit in stack-orchestrator repo.
|
- Checkout working commit in stack-orchestrator repo.
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
# In stack-orchestrator repo.
|
# In stack-orchestrator repo.
|
||||||
git checkout 3bb1796a59827fb755410c5ce69fac567a0f832b
|
git checkout main
|
||||||
```
|
```
|
||||||
|
|
||||||
## Run
|
## Run
|
||||||
|
29
test/contract/contracts/Test.sol
Normal file
29
test/contract/contracts/Test.sol
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
// SPDX-License-Identifier: AGPL-3.0
|
||||||
|
pragma solidity ^0.8.0;
|
||||||
|
|
||||||
|
contract Test {
|
||||||
|
address payable owner;
|
||||||
|
|
||||||
|
modifier onlyOwner {
|
||||||
|
require(
|
||||||
|
msg.sender == owner,
|
||||||
|
"Only owner can call this function."
|
||||||
|
);
|
||||||
|
_;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint256[100] data;
|
||||||
|
|
||||||
|
constructor() {
|
||||||
|
owner = payable(msg.sender);
|
||||||
|
data = [1];
|
||||||
|
}
|
||||||
|
|
||||||
|
function Put(uint256 addr, uint256 value) public {
|
||||||
|
data[addr] = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
function close() public onlyOwner {
|
||||||
|
selfdestruct(owner);
|
||||||
|
}
|
||||||
|
}
|
@ -63,6 +63,49 @@ fastify.get('/v1/sendEth', async (req, reply) => {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
fastify.get('/v1/deployTestContract', async (req, reply) => {
|
||||||
|
const testContract = await hre.ethers.getContractFactory("Test");
|
||||||
|
const test = await testContract.deploy();
|
||||||
|
await test.deployed();
|
||||||
|
|
||||||
|
return {
|
||||||
|
address: test.address,
|
||||||
|
txHash: test.deployTransaction.hash,
|
||||||
|
blockNumber: test.deployTransaction.blockNumber,
|
||||||
|
blockHash: test.deployTransaction.blockHash,
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
fastify.get('/v1/putTestValue', async (req, reply) => {
|
||||||
|
const addr = req.query.addr;
|
||||||
|
const index = req.query.index;
|
||||||
|
const value = req.query.value;
|
||||||
|
|
||||||
|
const testContract = await hre.ethers.getContractFactory("Test");
|
||||||
|
const test = await testContract.attach(addr);
|
||||||
|
|
||||||
|
const tx = await test.Put(index, value);
|
||||||
|
const receipt = await tx.wait();
|
||||||
|
|
||||||
|
return {
|
||||||
|
blockNumber: receipt.blockNumber,
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
fastify.get('/v1/destroyTestContract', async (req, reply) => {
|
||||||
|
const addr = req.query.addr;
|
||||||
|
|
||||||
|
const testContract = await hre.ethers.getContractFactory("Test");
|
||||||
|
const test = await testContract.attach(addr);
|
||||||
|
|
||||||
|
await test.destroy();
|
||||||
|
const blockNum = await hre.ethers.provider.getBlockNumber()
|
||||||
|
|
||||||
|
return {
|
||||||
|
blockNumber: blockNum,
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
async function main() {
|
async function main() {
|
||||||
try {
|
try {
|
||||||
await fastify.listen(3000, '0.0.0.0');
|
await fastify.listen(3000, '0.0.0.0');
|
||||||
@ -72,4 +115,4 @@ async function main() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
main();
|
main();
|
||||||
|
54
test/helper.go
Normal file
54
test/helper.go
Normal file
@ -0,0 +1,54 @@
|
|||||||
|
package integration
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
"net/http"
|
||||||
|
|
||||||
|
ethServerIntegration "github.com/vulcanize/ipld-eth-server/v3/test"
|
||||||
|
)
|
||||||
|
|
||||||
|
type PutResult struct {
|
||||||
|
BlockNumber int64 `json:"blockNumber"`
|
||||||
|
}
|
||||||
|
|
||||||
|
const srvUrl = "http://localhost:3000"
|
||||||
|
|
||||||
|
func DeployTestContract() (*ethServerIntegration.ContractDeployed, error) {
|
||||||
|
ethServerIntegration.DeployContract()
|
||||||
|
res, err := http.Get(fmt.Sprintf("%s/v1/deployTestContract", srvUrl))
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
defer res.Body.Close()
|
||||||
|
|
||||||
|
var contract ethServerIntegration.ContractDeployed
|
||||||
|
decoder := json.NewDecoder(res.Body)
|
||||||
|
|
||||||
|
return &contract, decoder.Decode(&contract)
|
||||||
|
}
|
||||||
|
|
||||||
|
func PutTestValue(addr string, index, value int) (*PutResult, error) {
|
||||||
|
res, err := http.Get(fmt.Sprintf("%s/v1/putTestValue?addr=%s&index=%d&value=%d", srvUrl, addr, index, value))
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
var blockNumber PutResult
|
||||||
|
decoder := json.NewDecoder(res.Body)
|
||||||
|
|
||||||
|
return &blockNumber, decoder.Decode(&blockNumber)
|
||||||
|
}
|
||||||
|
|
||||||
|
func DestroyTestContract(addr string) (*ethServerIntegration.ContractDestroyed, error) {
|
||||||
|
res, err := http.Get(fmt.Sprintf("%s/v1/destroyTestContract?addr=%s", srvUrl, addr))
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
defer res.Body.Close()
|
||||||
|
|
||||||
|
var data ethServerIntegration.ContractDestroyed
|
||||||
|
decoder := json.NewDecoder(res.Body)
|
||||||
|
|
||||||
|
return &data, decoder.Decode(&data)
|
||||||
|
}
|
@ -2,53 +2,107 @@ package integration_test
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
. "github.com/onsi/ginkgo"
|
. "github.com/onsi/ginkgo"
|
||||||
. "github.com/onsi/gomega"
|
. "github.com/onsi/gomega"
|
||||||
|
|
||||||
"github.com/vulcanize/ipld-eth-db-validator/pkg/validator"
|
"github.com/vulcanize/ipld-eth-db-validator/pkg/validator"
|
||||||
|
integration "github.com/vulcanize/ipld-eth-db-validator/test"
|
||||||
|
|
||||||
"github.com/vulcanize/ipld-eth-server/v3/pkg/shared"
|
"github.com/vulcanize/ipld-eth-server/v3/pkg/shared"
|
||||||
integration "github.com/vulcanize/ipld-eth-server/v3/test"
|
ethServerIntegration "github.com/vulcanize/ipld-eth-server/v3/test"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
|
blockNum = 1
|
||||||
trail = 0
|
trail = 0
|
||||||
validatorSleepInterval = uint(5)
|
validatorSleepInterval = uint(5)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
testAddresses = []string{
|
||||||
|
"0x1111111111111111111111111111111111111112",
|
||||||
|
"0x1ca7c995f8eF0A2989BbcE08D5B7Efe50A584aa1",
|
||||||
|
"0x9a4b666af23a2cdb4e5538e1d222a445aeb82134",
|
||||||
|
"0xF7C7AEaECD2349b129d5d15790241c32eeE4607B",
|
||||||
|
"0x992b6E9BFCA1F7b0797Cee10b0170E536EAd3532",
|
||||||
|
"0x29ed93a7454Bc17a8D4A24D0627009eE0849B990",
|
||||||
|
"0x66E3dCA826b04B5d4988F7a37c91c9b1041e579D",
|
||||||
|
"0x96288939Ac7048c27E0E087b02bDaad3cd61b37b",
|
||||||
|
"0xD354280BCd771541c935b15bc04342c26086FE9B",
|
||||||
|
"0x7f887e25688c274E77b8DeB3286A55129B55AF14",
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
var _ = Describe("Integration test", func() {
|
var _ = Describe("Integration test", func() {
|
||||||
ctx := context.Background()
|
ctx := context.Background()
|
||||||
|
|
||||||
var contract *integration.ContractDeployed
|
var contract *ethServerIntegration.ContractDeployed
|
||||||
var contractErr error
|
var err error
|
||||||
sleepInterval := 5 * time.Second
|
sleepInterval := 2 * time.Second
|
||||||
|
timeout := 4 * time.Second
|
||||||
|
|
||||||
|
db := shared.SetupDB()
|
||||||
|
cfg := validator.Config{
|
||||||
|
DB: db,
|
||||||
|
BlockNum: blockNum,
|
||||||
|
Trail: trail,
|
||||||
|
SleepInterval: validatorSleepInterval,
|
||||||
|
ChainCfg: validator.IntegrationTestChainConfig,
|
||||||
|
}
|
||||||
|
validationProgressChan := make(chan uint64)
|
||||||
|
service := validator.NewService(&cfg, validationProgressChan)
|
||||||
|
|
||||||
|
wg := new(sync.WaitGroup)
|
||||||
|
|
||||||
|
It("test init", func() {
|
||||||
|
wg.Add(1)
|
||||||
|
go service.Start(ctx, wg)
|
||||||
|
|
||||||
|
// Deploy a dummy contract as the first contract might get deployed at block number 0
|
||||||
|
_, _ = ethServerIntegration.DeployContract()
|
||||||
|
time.Sleep(sleepInterval)
|
||||||
|
})
|
||||||
|
|
||||||
|
defer It("test teardown", func() {
|
||||||
|
service.Stop()
|
||||||
|
wg.Wait()
|
||||||
|
|
||||||
|
Expect(validationProgressChan).To(BeClosed())
|
||||||
|
})
|
||||||
|
|
||||||
Describe("Validate state", func() {
|
Describe("Validate state", func() {
|
||||||
BeforeEach(func() {
|
It("performs validation on contract deployment", func() {
|
||||||
// Deploy a dummy contract as the first contract might get deployed at block number 0
|
contract, err = integration.DeployTestContract()
|
||||||
_, _ = integration.DeployContract()
|
Expect(err).ToNot(HaveOccurred())
|
||||||
time.Sleep(sleepInterval)
|
time.Sleep(sleepInterval)
|
||||||
|
|
||||||
contract, contractErr = integration.DeployContract()
|
Expect(validationProgressChan).ToNot(BeClosed())
|
||||||
time.Sleep(sleepInterval)
|
Eventually(validationProgressChan, timeout).Should(Receive(Equal(uint64(contract.BlockNumber))))
|
||||||
})
|
})
|
||||||
|
|
||||||
It("Validate state root", func() {
|
It("performs validation on contract transactions", func() {
|
||||||
Expect(contractErr).ToNot(HaveOccurred())
|
for i := 0; i < 10; i++ {
|
||||||
|
res, txErr := integration.PutTestValue(contract.Address, i, i)
|
||||||
|
Expect(txErr).ToNot(HaveOccurred())
|
||||||
|
time.Sleep(sleepInterval)
|
||||||
|
|
||||||
db := shared.SetupDB()
|
Expect(validationProgressChan).ToNot(BeClosed())
|
||||||
srvc := validator.NewService(db, uint64(contract.BlockNumber), trail, validatorSleepInterval, validator.IntegrationTestChainConfig)
|
Eventually(validationProgressChan, timeout).Should(Receive(Equal(uint64(res.BlockNumber))))
|
||||||
stopCh := make(chan int, 1)
|
}
|
||||||
go func() {
|
})
|
||||||
srvc.Start(ctx, nil)
|
|
||||||
stopCh <- 1
|
It("performs validation on eth transfer transactions", func() {
|
||||||
}()
|
for _, address := range testAddresses {
|
||||||
go func() {
|
tx, txErr := ethServerIntegration.SendEth(address, "0.01")
|
||||||
<-stopCh
|
Expect(txErr).ToNot(HaveOccurred())
|
||||||
srvc.Stop()
|
time.Sleep(sleepInterval)
|
||||||
}()
|
|
||||||
|
Expect(validationProgressChan).ToNot(BeClosed())
|
||||||
|
Eventually(validationProgressChan, timeout).Should(Receive(Equal(uint64(tx.BlockNumber))))
|
||||||
|
}
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
Loading…
Reference in New Issue
Block a user