-
Notifications
You must be signed in to change notification settings - Fork 64
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
9 changed files
with
532 additions
and
8 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,49 @@ | ||
// (c) Cartesi and individual authors (see AUTHORS) | ||
// SPDX-License-Identifier: Apache-2.0 (see LICENSE) | ||
|
||
package endtoendtests | ||
|
||
import ( | ||
"context" | ||
|
||
"github.com/cartesi/rollups-node/pkg/addresses" | ||
"github.com/cartesi/rollups-node/pkg/ethutil" | ||
"github.com/ethereum/go-ethereum/common/hexutil" | ||
"github.com/ethereum/go-ethereum/ethclient" | ||
"github.com/ethereum/go-ethereum/rpc" | ||
) | ||
|
||
func AddInput(ctx context.Context, | ||
blockchainHttpEnpoint string, payload string) (int, error) { | ||
|
||
// Send Input | ||
client, err := ethclient.DialContext(ctx, blockchainHttpEnpoint) | ||
if err != nil { | ||
return 0, err | ||
} | ||
defer client.Close() | ||
|
||
signer, err := ethutil.NewMnemonicSigner(ctx, client, ethutil.FoundryMnemonic, 0) | ||
if err != nil { | ||
return 0, err | ||
} | ||
book := addresses.GetTestBook() | ||
|
||
payloadBytes, _ := hexutil.Decode(payload) | ||
inputIndex, err := ethutil.AddInput(ctx, client, book, signer, payloadBytes) | ||
if err != nil { | ||
return 0, err | ||
} | ||
return inputIndex, nil | ||
|
||
} | ||
|
||
func AdvanceTime(ctx context.Context, blockchainHttpEnpoint string, timeInSeconds int) error { | ||
client, err := rpc.DialContext(ctx, blockchainHttpEnpoint) | ||
if err != nil { | ||
return err | ||
} | ||
defer client.Close() | ||
return client.CallContext(ctx, nil, "evm_increaseTime", timeInSeconds) | ||
|
||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,85 @@ | ||
// (c) Cartesi and individual authors (see AUTHORS) | ||
// SPDX-License-Identifier: Apache-2.0 (see LICENSE) | ||
|
||
// Package endtoendtests | ||
package endtoendtests | ||
|
||
import ( | ||
"fmt" | ||
"log/slog" | ||
"time" | ||
|
||
"github.com/cartesi/rollups-node/internal/node/config" | ||
"github.com/cartesi/rollups-node/pkg/addresses" | ||
"github.com/cartesi/rollups-node/pkg/ethutil" | ||
) | ||
|
||
const ( | ||
LocalPostgresEndpoint = "postgres://postgres:password@localhost:5432/postgres" | ||
LocalBlockchainID = 31337 | ||
LocalBlockchainHttpEndpoint = "http://localhost:8545" | ||
LocalBlockchainWsEnpoint = "ws://localhost:8545" | ||
LocalApplicationDeploymentBlockNumber = 20 | ||
LocalInputBoxDeploymentBlockNumber = 20 | ||
LocalHttpAddress = "0.0.0.0" | ||
LocalHttpPort = 10000 | ||
LocalBlockTimeout = 60 | ||
LocalFinalityOffset = 1 | ||
LocalEpochDurationInSeconds = 120 | ||
) | ||
|
||
func NewLocalNodeConfig() config.NodeConfig { | ||
var nodeConfig config.NodeConfig | ||
|
||
book := addresses.GetTestBook() | ||
|
||
//Log | ||
nodeConfig.LogLevel = slog.LevelInfo | ||
nodeConfig.LogPretty = false | ||
|
||
//Postgres | ||
nodeConfig.PostgresEndpoint = | ||
config.Redacted[string]{Value: LocalPostgresEndpoint} | ||
|
||
//Epoch | ||
nodeConfig.RollupsEpochDuration, _ = | ||
time.ParseDuration(fmt.Sprintf("%ds", LocalEpochDurationInSeconds)) | ||
|
||
//Blochain | ||
nodeConfig.BlockchainID = LocalBlockchainID | ||
nodeConfig.BlockchainHttpEndpoint = | ||
config.Redacted[string]{Value: LocalBlockchainHttpEndpoint} | ||
nodeConfig.BlockchainWsEndpoint = | ||
config.Redacted[string]{Value: LocalBlockchainWsEnpoint} | ||
nodeConfig.BlockchainIsLegacy = false | ||
nodeConfig.BlockchainFinalityOffset = LocalFinalityOffset | ||
nodeConfig.BlockchainBlockTimeout = LocalBlockTimeout | ||
|
||
//Contracts | ||
nodeConfig.ContractsHistoryAddress = book.HistoryAddress.Hex() | ||
nodeConfig.ContractsAuthorityAddress = book.AuthorityAddress.Hex() | ||
nodeConfig.ContractsApplicationAddress = book.CartesiDApp.Hex() | ||
nodeConfig.ContractsApplicationDeploymentBlockNumber = LocalApplicationDeploymentBlockNumber | ||
nodeConfig.ContractsInputBoxAddress = book.InputBox.Hex() | ||
nodeConfig.ContractsInputBoxDeploymentBlockNumber = LocalInputBoxDeploymentBlockNumber | ||
|
||
//HTTP endpoint | ||
nodeConfig.HttpAddress = LocalHttpAddress | ||
nodeConfig.HttpPort = LocalHttpPort | ||
|
||
//Features | ||
nodeConfig.FeatureHostMode = false | ||
nodeConfig.FeatureDisableClaimer = false | ||
nodeConfig.FeatureDisableMachineHashCheck = true | ||
|
||
//Experimental | ||
nodeConfig.ExperimentalSunodoValidatorEnabled = false | ||
|
||
//Auth | ||
nodeConfig.Auth = config.AuthMnemonic{ | ||
Mnemonic: config.Redacted[string]{Value: ethutil.FoundryMnemonic}, | ||
AccountIndex: config.Redacted[int]{Value: 0}, | ||
} | ||
|
||
return nodeConfig | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,246 @@ | ||
// (c) Cartesi and individual authors (see AUTHORS) | ||
// SPDX-License-Identifier: Apache-2.0 (see LICENSE) | ||
|
||
//go:build endtoendtests | ||
// +build endtoendtests | ||
|
||
package endtoendtests | ||
|
||
import ( | ||
"context" | ||
"encoding/json" | ||
"io/ioutil" | ||
"os" | ||
"path/filepath" | ||
"strings" | ||
"testing" | ||
"time" | ||
|
||
"github.com/Khan/genqlient/graphql" | ||
"github.com/cartesi/rollups-node/internal/deps" | ||
"github.com/cartesi/rollups-node/internal/machine" | ||
"github.com/cartesi/rollups-node/internal/node" | ||
"github.com/cartesi/rollups-node/pkg/readerclient" | ||
"github.com/ethereum/go-ethereum/common/hexutil" | ||
"github.com/stretchr/testify/assert" | ||
"github.com/stretchr/testify/require" | ||
"github.com/stretchr/testify/suite" | ||
) | ||
|
||
const ( | ||
payload = "0xdeadbeef" | ||
maxReadInputAttempts = 10 | ||
defaulTxDatabaseFile = "default_tx_database" | ||
) | ||
|
||
type EchoInputTestSuite struct { | ||
suite.Suite | ||
containers *deps.DepsContainers | ||
cancel context.CancelFunc | ||
tempDir string | ||
supervisorErr chan error | ||
} | ||
|
||
func (s *EchoInputTestSuite) SetupSuite() { | ||
|
||
// Clear default_tx_database | ||
cwd, err := os.Getwd() | ||
require.NoError(s.T(), err) | ||
|
||
_ = os.Remove(filepath.Join(cwd, defaulTxDatabaseFile)) | ||
|
||
// Create machine snapshot | ||
tempDir, err := ioutil.TempDir("", "machine-snapshot") | ||
assert.NoError(s.T(), err) | ||
machine.Save("cartesi/rollups-node-snapshot:devel", tempDir, "test-echo-app") | ||
|
||
// Run deps | ||
ctx := context.Background() | ||
var depsConfig = deps.NewDefaultDepsConfig() | ||
depsContainers, err := deps.Run(ctx, *depsConfig) | ||
assert.NoError(s.T(), err) | ||
|
||
// Wait a little for Dependencies to be actually ready | ||
time.Sleep(2 * time.Second) | ||
|
||
// Run Node Service | ||
nodeConfig := NewLocalNodeConfig() | ||
|
||
nodeConfig.SnapshotDir = tempDir | ||
|
||
ctx, cancel := context.WithCancel(ctx) | ||
supervisor, err := node.Setup(ctx, nodeConfig) | ||
require.NoError(s.T(), err) | ||
|
||
ready := make(chan struct{}, 1) | ||
supervisorErr := make(chan error, 1) | ||
go func() { | ||
err := supervisor.Start(ctx, ready) | ||
if err != nil { | ||
supervisorErr <- err | ||
} | ||
}() | ||
|
||
select { | ||
case err := <-supervisorErr: | ||
require.NoError(s.T(), err) | ||
case <-ready: | ||
break | ||
} | ||
|
||
// Configure Suite for tear down | ||
s.containers = depsContainers | ||
s.tempDir = tempDir | ||
s.cancel = cancel | ||
s.supervisorErr = supervisorErr | ||
|
||
} | ||
|
||
func (s *EchoInputTestSuite) TearDownSuite() { | ||
|
||
// Stop Node services | ||
s.cancel() | ||
|
||
// Remove machine snpshot | ||
os.RemoveAll(s.tempDir) | ||
|
||
// Terminate deps | ||
ctx := context.Background() | ||
err := deps.Terminate(ctx, s.containers) | ||
require.NoError(s.T(), err) | ||
|
||
// Clear default_tx_database | ||
cwd, err := os.Getwd() | ||
require.NoError(s.T(), err) | ||
|
||
_ = os.Remove(filepath.Join(cwd, defaulTxDatabaseFile)) | ||
|
||
} | ||
|
||
func (s *EchoInputTestSuite) SetupTest() { | ||
|
||
} | ||
|
||
func (s *EchoInputTestSuite) TestSendInput() { | ||
|
||
ctx := context.Background() | ||
|
||
inputIndex, err := AddInput(ctx, LocalBlockchainHttpEndpoint, payload) | ||
require.NoError(s.T(), err) | ||
|
||
// Check input was correctly added to the blockchain | ||
require.EqualValues(s.T(), 0, inputIndex) | ||
|
||
require.NoError(s.T(), AdvanceTime(ctx, LocalBlockchainHttpEndpoint, 120)) | ||
|
||
// Get Input with vouchers and proofs | ||
graphQlClient := graphql.NewClient("http://localhost:10000/graphql", nil) | ||
getInputChan := make(chan *readerclient.Input, 1) | ||
getInputErr := make(chan struct{}, 1) | ||
|
||
go func() { | ||
var resp *readerclient.Input | ||
attempts := 0 | ||
for ; attempts < maxReadInputAttempts; attempts++ { | ||
time.Sleep(2 * time.Second) | ||
resp, err = readerclient.GetInput(ctx, graphQlClient, inputIndex) | ||
if err == nil && resp.Status == "ACCEPTED" && resp.Vouchers != nil && resp.Vouchers[0].Proof != nil { | ||
break | ||
} | ||
} | ||
if attempts == maxReadInputAttempts { | ||
getInputErr <- struct{}{} | ||
return | ||
} | ||
getInputChan <- resp | ||
}() | ||
|
||
select { | ||
case input := <-getInputChan: | ||
|
||
//Check Input Fields | ||
|
||
require.EqualValues(s.T(), 0, input.Index) | ||
require.EqualValues(s.T(), "ACCEPTED", input.Status) | ||
require.EqualValues(s.T(), payload, hexutil.Encode(input.Payload)) | ||
|
||
//Check Notices | ||
|
||
require.NotNil(s.T(), input.Notices) | ||
require.EqualValues(s.T(), 1, len(input.Notices)) | ||
require.EqualValues(s.T(), 0, input.Notices[0].Index) | ||
require.EqualValues(s.T(), 0, input.Notices[0].InputIndex) | ||
require.EqualValues(s.T(), payload, hexutil.Encode(input.Notices[0].Payload)) | ||
|
||
expectedProof, err := readExpectedProof("expected_notice_proof.json") | ||
require.NoError(s.T(), err) | ||
|
||
checkProof(s, expectedProof, input.Notices[0].Proof) | ||
|
||
// Check Vouchers | ||
|
||
require.NotNil(s.T(), input.Vouchers) | ||
require.EqualValues(s.T(), 1, len(input.Vouchers)) | ||
require.EqualValues(s.T(), 0, input.Vouchers[0].Index) | ||
require.EqualValues(s.T(), 0, input.Vouchers[0].InputIndex) | ||
require.EqualValues(s.T(), "0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266", strings.ToLower(input.Vouchers[0].Destination.Hex())) | ||
require.EqualValues(s.T(), payload, hexutil.Encode(input.Vouchers[0].Payload)) | ||
|
||
expectedProof, err = readExpectedProof("expected_voucher_proof.json") | ||
require.NoError(s.T(), err) | ||
|
||
checkProof(s, expectedProof, input.Vouchers[0].Proof) | ||
|
||
// Check Reports | ||
|
||
require.NotNil(s.T(), input.Reports) | ||
require.EqualValues(s.T(), 1, len(input.Reports)) | ||
require.EqualValues(s.T(), 0, input.Reports[0].Index) | ||
require.EqualValues(s.T(), 0, input.Reports[0].InputIndex) | ||
require.EqualValues(s.T(), payload, hexutil.Encode(input.Reports[0].Payload)) | ||
|
||
break | ||
case err = <-s.supervisorErr: | ||
require.NoError(s.T(), err) | ||
break | ||
case <-getInputErr: | ||
require.FailNow(s.T(), "Could not retrieve Voucher with Proof 0") | ||
} | ||
|
||
} | ||
|
||
func readExpectedProof(proofFileName string) (*readerclient.Proof, error) { | ||
cwd, err := os.Getwd() | ||
if err != nil { | ||
return nil, err | ||
} | ||
|
||
expectedProofJsonBytes, err := ioutil.ReadFile(filepath.Join(cwd, "resources", "echo_input", proofFileName)) | ||
if err != nil { | ||
return nil, err | ||
} | ||
|
||
var proof readerclient.Proof | ||
err = json.Unmarshal(expectedProofJsonBytes, &proof) | ||
if err != nil { | ||
return nil, err | ||
} | ||
|
||
return &proof, nil | ||
|
||
} | ||
|
||
func checkProof(s *EchoInputTestSuite, expectedProof *readerclient.Proof, proof *readerclient.Proof) { | ||
|
||
// Machine state hashes are different between runs | ||
proof.MachineStateHash = nil | ||
expectedProof.MachineStateHash = nil | ||
|
||
require.EqualValues(s.T(), expectedProof, proof) | ||
|
||
} | ||
|
||
func TestEchoInput(t *testing.T) { | ||
|
||
suite.Run(t, new(EchoInputTestSuite)) | ||
} |
Oops, something went wrong.