diff --git a/cmd/cartesi-rollups-cli/root/send/send.go b/cmd/cartesi-rollups-cli/root/send/send.go index 81010081f..af69bfb3c 100644 --- a/cmd/cartesi-rollups-cli/root/send/send.go +++ b/cmd/cartesi-rollups-cli/root/send/send.go @@ -51,6 +51,7 @@ func init() { } func run(cmd *cobra.Command, args []string) { + payload, err := hexutil.Decode(hexPayload) cobra.CheckErr(err) diff --git a/end-to-end-tests/config.go b/end-to-end-tests/config.go new file mode 100644 index 000000000..471b65d73 --- /dev/null +++ b/end-to-end-tests/config.go @@ -0,0 +1,75 @@ +package endtoendtests + +import ( + "log/slog" + + "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 + LocalEpochDuration = 120 +) + +func newLocalNodeConfig() config.NodeConfig { + var nodeConfig config.NodeConfig + + book := addresses.GetTestBook() + + //Log + nodeConfig.Log.Level = slog.LevelInfo + nodeConfig.Log.Pretty = false + + //Postgres + nodeConfig.PostgresEndpoint = config.Redacted[string]{LocalPostgresEndpoint} + + //Epoch + nodeConfig.RollupsEpochDuration = LocalEpochDuration + + //Blochain + nodeConfig.Blockchain.ID = LocalBlockchainID + nodeConfig.Blockchain.HttpEndpoint = config.Redacted[string]{LocalBlockchainHttpEndpoint} + nodeConfig.Blockchain.WsEndpoint = config.Redacted[string]{LocalBlockchainWsEnpoint} + nodeConfig.Blockchain.IsLegacy = false + nodeConfig.Blockchain.FinalityOffset = LocalFinalityOffset + nodeConfig.Blockchain.BlockTimeout = LocalBlockTimeout + + //Contracts + nodeConfig.Contracts.HistoryAddress = book.HistoryAddress.Hex() + nodeConfig.Contracts.AuthorityAddress = book.AuthorityAddress.Hex() + nodeConfig.Contracts.ApplicationAddress = book.CartesiDApp.Hex() + nodeConfig.Contracts.ApplicationDeploymentBlockNumber = LocalApplicationDeploymentBlockNumber + nodeConfig.Contracts.InputBoxAddress = book.InputBox.Hex() + nodeConfig.Contracts.InputBoxDeploymentBlockNumber = LocalInputBoxDeploymentBlockNumber + + //HTTP endpoint + nodeConfig.Http.Address = LocalHttpAddress + nodeConfig.Http.Port = LocalHttpPort + + //Features + nodeConfig.Feature.HostMode = false + nodeConfig.Feature.DisableClaimer = false + nodeConfig.Feature.DisableMachineHashCheck = true + + //Experimental + nodeConfig.Experimental.SunodoValidatorEnabled = false + + //Auth + nodeConfig.Auth = config.AuthMnemonic{ + config.Redacted[string]{ethutil.FoundryMnemonic}, + config.Redacted[int]{0}, + } + + return nodeConfig +} diff --git a/end-to-end-tests/echo_input_test.go b/end-to-end-tests/echo_input_test.go index 46ba78d0e..fcc74f190 100644 --- a/end-to-end-tests/echo_input_test.go +++ b/end-to-end-tests/echo_input_test.go @@ -4,28 +4,153 @@ package endtoendtests import ( + "context" + "fmt" + "io/ioutil" + "os" "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/addresses" + "github.com/cartesi/rollups-node/pkg/ethutil" + "github.com/cartesi/rollups-node/pkg/readerclient" + "github.com/ethereum/go-ethereum/ethclient" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" "github.com/stretchr/testify/suite" ) type EchoInputTestSuite struct { suite.Suite + containers *deps.DepsContainers + cancel context.CancelFunc + tempDir string + supervisorErr chan error } func (s *EchoInputTestSuite) SetupSuite() { - //run services + //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) + + fmt.Println("All Deps are up!!") + 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: + fmt.Println("All services are up!!") + 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) + } func (s *EchoInputTestSuite) SetupTest() { } +func (s *EchoInputTestSuite) TestSendInput() { + + ctx := context.Background() + + // Send Input + client, err := ethclient.DialContext(ctx, "http://localhost:8545") + require.NoError(s.T(), err) + signer, err := ethutil.NewMnemonicSigner(ctx, client, ethutil.FoundryMnemonic, 0) + require.NoError(s.T(), err) + + book := addresses.GetTestBook() + + inputIndex, err := ethutil.AddInput(ctx, client, book, signer, []byte("0xDEADBEEF")) + require.NoError(s.T(), err) + + require.EqualValues(s.T(), 0, inputIndex, "The input index should be 0") + + //Check Input if input is Processed + graphQlClient := graphql.NewClient("http://localhost:10000/graphql", nil) + + getInputChan := make(chan *readerclient.Input, 1) + getInputErr := make(chan struct{}, 1) + go func() { + fmt.Println("Waiting for Input...") + time.Sleep(2 * time.Second) + var resp *readerclient.Input + attempts := 0 + for resp, err = readerclient.GetInput(ctx, graphQlClient, inputIndex); err != nil || attempts < 10; attempts++ { + fmt.Printf("Error : %v \n", err) + fmt.Println("Waiting for Input...") + time.Sleep(2 * time.Second) + } + if attempts == 10 { + getInputErr <- struct{}{} + return + } + getInputChan <- resp + }() + + select { + case resp := <-getInputChan: + fmt.Printf("Response %v \n", resp) + break + case err = <-s.supervisorErr: + require.NoError(s.T(), err) + } + +} + func TestEchoInput(t *testing.T) { + suite.Run(t, new(EchoInputTestSuite)) } diff --git a/internal/deps/deps.go b/internal/deps/deps.go index ea4e9f37b..3f6a02247 100644 --- a/internal/deps/deps.go +++ b/internal/deps/deps.go @@ -55,12 +55,19 @@ type DepsContainers struct { } func createHook(containerName string, - waitGroup *sync.WaitGroup) []testcontainers.ContainerLifecycleHooks { + finishedWaitGroup *sync.WaitGroup, + startedWaitGroup *sync.WaitGroup) []testcontainers.ContainerLifecycleHooks { return []testcontainers.ContainerLifecycleHooks{ { + PostStarts: []testcontainers.ContainerHook{ + func(ctx context.Context, container testcontainers.Container) error { + startedWaitGroup.Done() + return nil + }, + }, PostTerminates: []testcontainers.ContainerHook{ func(ctx context.Context, container testcontainers.Container) error { - waitGroup.Done() + finishedWaitGroup.Done() return nil }, }, @@ -73,14 +80,17 @@ func createHook(containerName string, // The returned DepContainers struct can be used to gracefully // terminate the containers using the Terminate method func Run(ctx context.Context, depsConfig DepsConfig) (*DepsContainers, error) { + noopLogger := log.New(io.Discard, "", 0) - var waitGroup sync.WaitGroup + var finishedWaitGroup sync.WaitGroup + var startedWaitGroup sync.WaitGroup // wait strategy copied from testcontainers docs postgresWaitStrategy := wait.ForLog("database system is ready to accept connections"). WithOccurrence(numPostgresCheckReadyAttempts). WithPollInterval(pollInterval) + startedWaitGroup.Add(1) postgresReq := testcontainers.ContainerRequest{ Image: depsConfig.PostgresDockerImage, ExposedPorts: []string{strings.Join([]string{ @@ -90,7 +100,7 @@ func Run(ctx context.Context, depsConfig DepsConfig) (*DepsContainers, error) { Env: map[string]string{ "POSTGRES_PASSWORD": depsConfig.PostgresPassword, }, - LifecycleHooks: createHook("rollups-node-dep-postgres", &waitGroup), + LifecycleHooks: createHook("rollups-node-dep-postgres", &finishedWaitGroup, &startedWaitGroup), } postgres, err := testcontainers.GenericContainer(ctx, testcontainers.GenericContainerRequest{ @@ -102,8 +112,9 @@ func Run(ctx context.Context, depsConfig DepsConfig) (*DepsContainers, error) { if err != nil { return nil, err } - waitGroup.Add(1) + finishedWaitGroup.Add(1) + startedWaitGroup.Add(1) devNetReq := testcontainers.ContainerRequest{ Image: depsConfig.DevnetDockerImage, ExposedPorts: []string{strings.Join([]string{depsConfig.DevnetPort, ":8545/tcp"}, "")}, @@ -112,7 +123,7 @@ func Run(ctx context.Context, depsConfig DepsConfig) (*DepsContainers, error) { Env: map[string]string{ "ANVIL_IP_ADDR": "0.0.0.0", }, - LifecycleHooks: createHook("rollups-node-dep-devnet", &waitGroup), + LifecycleHooks: createHook("rollups-node-dep-devnet", &finishedWaitGroup, &startedWaitGroup), } devnet, err := testcontainers.GenericContainer(ctx, testcontainers.GenericContainerRequest{ @@ -124,11 +135,12 @@ func Run(ctx context.Context, depsConfig DepsConfig) (*DepsContainers, error) { return nil, err } - waitGroup.Add(1) + finishedWaitGroup.Add(1) containers := []testcontainers.Container{postgres, devnet} - return &DepsContainers{containers, &waitGroup}, nil + startedWaitGroup.Wait() + return &DepsContainers{containers, &finishedWaitGroup}, nil } // Terminate terminates all dependencies containers. This method waits for all the containers diff --git a/pkg/addresses/addresses.go b/pkg/addresses/addresses.go index 8a2c490ff..1bac01d16 100644 --- a/pkg/addresses/addresses.go +++ b/pkg/addresses/addresses.go @@ -29,6 +29,8 @@ type Book struct { EtherPortal common.Address InputBox common.Address CartesiDApp common.Address + HistoryAddress common.Address + AuthorityAddress common.Address } // Get the addresses for the test environment. @@ -45,6 +47,8 @@ func GetTestBook() *Book { EtherPortal: common.HexToAddress("0xFfdbe43d4c855BF7e0f105c400A50857f53AB044"), InputBox: common.HexToAddress("0x59b22D57D4f067708AB0c00552767405926dc768"), CartesiDApp: common.HexToAddress("0x7FFdf694A877067DE99462A7243b29972D19cf72"), + HistoryAddress: common.HexToAddress("0x325272217ae6815b494bF38cED004c5Eb8a7CdA7"), + AuthorityAddress: common.HexToAddress("0x58c93F83fb3304730C95aad2E360cdb88b782010"), } }