diff --git a/cmd/cartesi-rollups-cli/root/read/notices/notices.go b/cmd/cartesi-rollups-cli/root/read/notices/notices.go new file mode 100644 index 000000000..c03a78232 --- /dev/null +++ b/cmd/cartesi-rollups-cli/root/read/notices/notices.go @@ -0,0 +1,57 @@ +// (c) Cartesi and individual authors (see AUTHORS) +// SPDX-License-Identifier: Apache-2.0 (see LICENSE) + +package notices + +import ( + "encoding/json" + "fmt" + + "github.com/Khan/genqlient/graphql" + "github.com/cartesi/rollups-node/pkg/readerclient" + "github.com/spf13/cobra" +) + +var Cmd = &cobra.Command{ + Use: "notices", + Short: "Reads notices; if there's an input index, reads notices from that input", + Example: examples, + Run: run, +} + +const examples = `# Read notices from GraphQL; if there's an input-index, reads notices from that input: +cartesi-rollups-cli read notices` + +var ( + inputIndex int + graphqlEndpoint string +) + +func init() { + Cmd.Flags().IntVar(&inputIndex, "input-index", -1, + "index of the input") + + Cmd.Flags().StringVar(&graphqlEndpoint, "graphql-endpoint", "http://0.0.0.0:4000/graphql", + "address used to connect to graphql") +} + +func run(cmd *cobra.Command, args []string) { + ctx := cmd.Context() + client := graphql.NewClient(graphqlEndpoint, nil) + + var resp []readerclient.Notice + var err error + + if inputIndex != -1 { + resp, err = readerclient.GetInputNotices(ctx, client, inputIndex) + cobra.CheckErr(err) + } else { + resp, err = readerclient.GetNotices(ctx, client) + cobra.CheckErr(err) + } + + val, err := json.MarshalIndent(resp, "", " ") + cobra.CheckErr(err) + + fmt.Print(string(val)) +} diff --git a/cmd/cartesi-rollups-cli/root/read/read.go b/cmd/cartesi-rollups-cli/root/read/read.go index 226ba1f2b..78f3a991e 100644 --- a/cmd/cartesi-rollups-cli/root/read/read.go +++ b/cmd/cartesi-rollups-cli/root/read/read.go @@ -7,6 +7,7 @@ import ( "github.com/cartesi/rollups-node/cmd/cartesi-rollups-cli/root/read/input" "github.com/cartesi/rollups-node/cmd/cartesi-rollups-cli/root/read/inputs" "github.com/cartesi/rollups-node/cmd/cartesi-rollups-cli/root/read/notice" + "github.com/cartesi/rollups-node/cmd/cartesi-rollups-cli/root/read/notices" "github.com/spf13/cobra" ) @@ -19,4 +20,5 @@ func init() { Cmd.AddCommand(input.Cmd) Cmd.AddCommand(inputs.Cmd) Cmd.AddCommand(notice.Cmd) + Cmd.AddCommand(notices.Cmd) } diff --git a/pkg/readerclient/generate/input_notices.graphql b/pkg/readerclient/generate/input_notices.graphql new file mode 100644 index 000000000..bd86be180 --- /dev/null +++ b/pkg/readerclient/generate/input_notices.graphql @@ -0,0 +1,26 @@ +query getInputNotices($inputIndex: Int!) { + input(index: $inputIndex) { + index + notices { + edges { + node{ + index + payload + proof { + validity { + inputIndexWithinEpoch + outputIndexWithinInput + outputHashesRootHash + vouchersEpochRootHash + noticesEpochRootHash + machineStateHash + outputHashInOutputHashesSiblings + outputHashesInEpochSiblings + } + context + } + } + } + } + } +} diff --git a/pkg/readerclient/generate/notices.graphql b/pkg/readerclient/generate/notices.graphql new file mode 100644 index 000000000..ae6961cb2 --- /dev/null +++ b/pkg/readerclient/generate/notices.graphql @@ -0,0 +1,26 @@ +query getNotices { + notices { + edges { + node { + index + payload + proof { + validity { + inputIndexWithinEpoch + outputIndexWithinInput + outputHashesRootHash + vouchersEpochRootHash + noticesEpochRootHash + machineStateHash + outputHashInOutputHashesSiblings + outputHashesInEpochSiblings + } + context + } + input { + index + } + } + } + } +} diff --git a/pkg/readerclient/generated.go b/pkg/readerclient/generated.go index 9881d4678..41127ba96 100644 --- a/pkg/readerclient/generated.go +++ b/pkg/readerclient/generated.go @@ -29,6 +29,26 @@ type __getInputInput struct { // GetIndex returns __getInputInput.Index, and is useful for accessing the field via an interface. func (v *__getInputInput) GetIndex() int { return v.Index } +// __getInputNoticesInput is used internally by genqlient +type __getInputNoticesInput struct { + InputIndex int `json:"inputIndex"` +} + +// GetInputIndex returns __getInputNoticesInput.InputIndex, and is useful for accessing the field via an interface. +func (v *__getInputNoticesInput) GetInputIndex() int { return v.InputIndex } + +// __getNoticeInput is used internally by genqlient +type __getNoticeInput struct { + NoticeIndex int `json:"noticeIndex"` + InputIndex int `json:"inputIndex"` +} + +// GetNoticeIndex returns __getNoticeInput.NoticeIndex, and is useful for accessing the field via an interface. +func (v *__getNoticeInput) GetNoticeIndex() int { return v.NoticeIndex } + +// GetInputIndex returns __getNoticeInput.InputIndex, and is useful for accessing the field via an interface. +func (v *__getNoticeInput) GetInputIndex() int { return v.InputIndex } + // getInputInput includes the requested fields of the GraphQL type Input. // The GraphQL type's documentation follows. // @@ -66,6 +86,174 @@ func (v *getInputInput) GetBlockNumber() string { return v.BlockNumber } // GetPayload returns getInputInput.Payload, and is useful for accessing the field via an interface. func (v *getInputInput) GetPayload() string { return v.Payload } +// getInputNoticesInput includes the requested fields of the GraphQL type Input. +// The GraphQL type's documentation follows. +// +// Request submitted to the application to advance its state +type getInputNoticesInput struct { + // Input index starting from genesis + Index int `json:"index"` + // Get notices from this particular input with support for pagination + Notices getInputNoticesInputNoticesNoticeConnection `json:"notices"` +} + +// GetIndex returns getInputNoticesInput.Index, and is useful for accessing the field via an interface. +func (v *getInputNoticesInput) GetIndex() int { return v.Index } + +// GetNotices returns getInputNoticesInput.Notices, and is useful for accessing the field via an interface. +func (v *getInputNoticesInput) GetNotices() getInputNoticesInputNoticesNoticeConnection { + return v.Notices +} + +// getInputNoticesInputNoticesNoticeConnection includes the requested fields of the GraphQL type NoticeConnection. +// The GraphQL type's documentation follows. +// +// Pagination result +type getInputNoticesInputNoticesNoticeConnection struct { + // Pagination entries returned for the current page + Edges []getInputNoticesInputNoticesNoticeConnectionEdgesNoticeEdge `json:"edges"` +} + +// GetEdges returns getInputNoticesInputNoticesNoticeConnection.Edges, and is useful for accessing the field via an interface. +func (v *getInputNoticesInputNoticesNoticeConnection) GetEdges() []getInputNoticesInputNoticesNoticeConnectionEdgesNoticeEdge { + return v.Edges +} + +// getInputNoticesInputNoticesNoticeConnectionEdgesNoticeEdge includes the requested fields of the GraphQL type NoticeEdge. +// The GraphQL type's documentation follows. +// +// Pagination entry +type getInputNoticesInputNoticesNoticeConnectionEdgesNoticeEdge struct { + // Node instance + Node getInputNoticesInputNoticesNoticeConnectionEdgesNoticeEdgeNodeNotice `json:"node"` +} + +// GetNode returns getInputNoticesInputNoticesNoticeConnectionEdgesNoticeEdge.Node, and is useful for accessing the field via an interface. +func (v *getInputNoticesInputNoticesNoticeConnectionEdgesNoticeEdge) GetNode() getInputNoticesInputNoticesNoticeConnectionEdgesNoticeEdgeNodeNotice { + return v.Node +} + +// getInputNoticesInputNoticesNoticeConnectionEdgesNoticeEdgeNodeNotice includes the requested fields of the GraphQL type Notice. +// The GraphQL type's documentation follows. +// +// Informational statement that can be validated in the base layer blockchain +type getInputNoticesInputNoticesNoticeConnectionEdgesNoticeEdgeNodeNotice struct { + // Notice index within the context of the input that produced it + Index int `json:"index"` + // Notice data as a payload in Ethereum hex binary format, starting with '0x' + Payload string `json:"payload"` + // Proof object that allows this notice to be validated by the base layer blockchain + Proof getInputNoticesInputNoticesNoticeConnectionEdgesNoticeEdgeNodeNoticeProof `json:"proof"` +} + +// GetIndex returns getInputNoticesInputNoticesNoticeConnectionEdgesNoticeEdgeNodeNotice.Index, and is useful for accessing the field via an interface. +func (v *getInputNoticesInputNoticesNoticeConnectionEdgesNoticeEdgeNodeNotice) GetIndex() int { + return v.Index +} + +// GetPayload returns getInputNoticesInputNoticesNoticeConnectionEdgesNoticeEdgeNodeNotice.Payload, and is useful for accessing the field via an interface. +func (v *getInputNoticesInputNoticesNoticeConnectionEdgesNoticeEdgeNodeNotice) GetPayload() string { + return v.Payload +} + +// GetProof returns getInputNoticesInputNoticesNoticeConnectionEdgesNoticeEdgeNodeNotice.Proof, and is useful for accessing the field via an interface. +func (v *getInputNoticesInputNoticesNoticeConnectionEdgesNoticeEdgeNodeNotice) GetProof() getInputNoticesInputNoticesNoticeConnectionEdgesNoticeEdgeNodeNoticeProof { + return v.Proof +} + +// getInputNoticesInputNoticesNoticeConnectionEdgesNoticeEdgeNodeNoticeProof includes the requested fields of the GraphQL type Proof. +// The GraphQL type's documentation follows. +// +// Data that can be used as proof to validate notices and execute vouchers on the base layer blockchain +type getInputNoticesInputNoticesNoticeConnectionEdgesNoticeEdgeNodeNoticeProof struct { + // Validity proof for an output + Validity getInputNoticesInputNoticesNoticeConnectionEdgesNoticeEdgeNodeNoticeProofValidityOutputValidityProof `json:"validity"` + // Data that allows the validity proof to be contextualized within submitted claims, given as a payload in Ethereum hex binary format, starting with '0x' + Context string `json:"context"` +} + +// GetValidity returns getInputNoticesInputNoticesNoticeConnectionEdgesNoticeEdgeNodeNoticeProof.Validity, and is useful for accessing the field via an interface. +func (v *getInputNoticesInputNoticesNoticeConnectionEdgesNoticeEdgeNodeNoticeProof) GetValidity() getInputNoticesInputNoticesNoticeConnectionEdgesNoticeEdgeNodeNoticeProofValidityOutputValidityProof { + return v.Validity +} + +// GetContext returns getInputNoticesInputNoticesNoticeConnectionEdgesNoticeEdgeNodeNoticeProof.Context, and is useful for accessing the field via an interface. +func (v *getInputNoticesInputNoticesNoticeConnectionEdgesNoticeEdgeNodeNoticeProof) GetContext() string { + return v.Context +} + +// getInputNoticesInputNoticesNoticeConnectionEdgesNoticeEdgeNodeNoticeProofValidityOutputValidityProof includes the requested fields of the GraphQL type OutputValidityProof. +// The GraphQL type's documentation follows. +// +// Validity proof for an output +type getInputNoticesInputNoticesNoticeConnectionEdgesNoticeEdgeNodeNoticeProofValidityOutputValidityProof struct { + // Local input index within the context of the related epoch + InputIndexWithinEpoch int `json:"inputIndexWithinEpoch"` + // Output index within the context of the input that produced it + OutputIndexWithinInput int `json:"outputIndexWithinInput"` + // Merkle root of all output hashes of the related input, given in Ethereum hex binary format (32 bytes), starting with '0x' + OutputHashesRootHash string `json:"outputHashesRootHash"` + // Merkle root of all voucher hashes of the related epoch, given in Ethereum hex binary format (32 bytes), starting with '0x' + VouchersEpochRootHash string `json:"vouchersEpochRootHash"` + // Merkle root of all notice hashes of the related epoch, given in Ethereum hex binary format (32 bytes), starting with '0x' + NoticesEpochRootHash string `json:"noticesEpochRootHash"` + // Hash of the machine state claimed for the related epoch, given in Ethereum hex binary format (32 bytes), starting with '0x' + MachineStateHash string `json:"machineStateHash"` + // Proof that this output hash is in the output-hashes merkle tree. This array of siblings is bottom-up ordered (from the leaf to the root). Each hash is given in Ethereum hex binary format (32 bytes), starting with '0x'. + OutputHashInOutputHashesSiblings []string `json:"outputHashInOutputHashesSiblings"` + // Proof that this output-hashes root hash is in epoch's output merkle tree. This array of siblings is bottom-up ordered (from the leaf to the root). Each hash is given in Ethereum hex binary format (32 bytes), starting with '0x'. + OutputHashesInEpochSiblings []string `json:"outputHashesInEpochSiblings"` +} + +// GetInputIndexWithinEpoch returns getInputNoticesInputNoticesNoticeConnectionEdgesNoticeEdgeNodeNoticeProofValidityOutputValidityProof.InputIndexWithinEpoch, and is useful for accessing the field via an interface. +func (v *getInputNoticesInputNoticesNoticeConnectionEdgesNoticeEdgeNodeNoticeProofValidityOutputValidityProof) GetInputIndexWithinEpoch() int { + return v.InputIndexWithinEpoch +} + +// GetOutputIndexWithinInput returns getInputNoticesInputNoticesNoticeConnectionEdgesNoticeEdgeNodeNoticeProofValidityOutputValidityProof.OutputIndexWithinInput, and is useful for accessing the field via an interface. +func (v *getInputNoticesInputNoticesNoticeConnectionEdgesNoticeEdgeNodeNoticeProofValidityOutputValidityProof) GetOutputIndexWithinInput() int { + return v.OutputIndexWithinInput +} + +// GetOutputHashesRootHash returns getInputNoticesInputNoticesNoticeConnectionEdgesNoticeEdgeNodeNoticeProofValidityOutputValidityProof.OutputHashesRootHash, and is useful for accessing the field via an interface. +func (v *getInputNoticesInputNoticesNoticeConnectionEdgesNoticeEdgeNodeNoticeProofValidityOutputValidityProof) GetOutputHashesRootHash() string { + return v.OutputHashesRootHash +} + +// GetVouchersEpochRootHash returns getInputNoticesInputNoticesNoticeConnectionEdgesNoticeEdgeNodeNoticeProofValidityOutputValidityProof.VouchersEpochRootHash, and is useful for accessing the field via an interface. +func (v *getInputNoticesInputNoticesNoticeConnectionEdgesNoticeEdgeNodeNoticeProofValidityOutputValidityProof) GetVouchersEpochRootHash() string { + return v.VouchersEpochRootHash +} + +// GetNoticesEpochRootHash returns getInputNoticesInputNoticesNoticeConnectionEdgesNoticeEdgeNodeNoticeProofValidityOutputValidityProof.NoticesEpochRootHash, and is useful for accessing the field via an interface. +func (v *getInputNoticesInputNoticesNoticeConnectionEdgesNoticeEdgeNodeNoticeProofValidityOutputValidityProof) GetNoticesEpochRootHash() string { + return v.NoticesEpochRootHash +} + +// GetMachineStateHash returns getInputNoticesInputNoticesNoticeConnectionEdgesNoticeEdgeNodeNoticeProofValidityOutputValidityProof.MachineStateHash, and is useful for accessing the field via an interface. +func (v *getInputNoticesInputNoticesNoticeConnectionEdgesNoticeEdgeNodeNoticeProofValidityOutputValidityProof) GetMachineStateHash() string { + return v.MachineStateHash +} + +// GetOutputHashInOutputHashesSiblings returns getInputNoticesInputNoticesNoticeConnectionEdgesNoticeEdgeNodeNoticeProofValidityOutputValidityProof.OutputHashInOutputHashesSiblings, and is useful for accessing the field via an interface. +func (v *getInputNoticesInputNoticesNoticeConnectionEdgesNoticeEdgeNodeNoticeProofValidityOutputValidityProof) GetOutputHashInOutputHashesSiblings() []string { + return v.OutputHashInOutputHashesSiblings +} + +// GetOutputHashesInEpochSiblings returns getInputNoticesInputNoticesNoticeConnectionEdgesNoticeEdgeNodeNoticeProofValidityOutputValidityProof.OutputHashesInEpochSiblings, and is useful for accessing the field via an interface. +func (v *getInputNoticesInputNoticesNoticeConnectionEdgesNoticeEdgeNodeNoticeProofValidityOutputValidityProof) GetOutputHashesInEpochSiblings() []string { + return v.OutputHashesInEpochSiblings +} + +// getInputNoticesResponse is returned by getInputNotices on success. +type getInputNoticesResponse struct { + // Get input based on its identifier + Input getInputNoticesInput `json:"input"` +} + +// GetInput returns getInputNoticesResponse.Input, and is useful for accessing the field via an interface. +func (v *getInputNoticesResponse) GetInput() getInputNoticesInput { return v.Input } + // getInputResponse is returned by getInput on success. type getInputResponse struct { // Get input based on its identifier @@ -280,13 +468,181 @@ func (v *getNoticeNoticeProofValidityOutputValidityProof) GetOutputHashesInEpoch // getNoticeResponse is returned by getNotice on success. type getNoticeResponse struct { - // Get notice based on its index + // Get a notice based on its index Notice getNoticeNotice `json:"notice"` } // GetNotice returns getNoticeResponse.Notice, and is useful for accessing the field via an interface. func (v *getNoticeResponse) GetNotice() getNoticeNotice { return v.Notice } +// getNoticesNoticesNoticeConnection includes the requested fields of the GraphQL type NoticeConnection. +// The GraphQL type's documentation follows. +// +// Pagination result +type getNoticesNoticesNoticeConnection struct { + // Pagination entries returned for the current page + Edges []getNoticesNoticesNoticeConnectionEdgesNoticeEdge `json:"edges"` +} + +// GetEdges returns getNoticesNoticesNoticeConnection.Edges, and is useful for accessing the field via an interface. +func (v *getNoticesNoticesNoticeConnection) GetEdges() []getNoticesNoticesNoticeConnectionEdgesNoticeEdge { + return v.Edges +} + +// getNoticesNoticesNoticeConnectionEdgesNoticeEdge includes the requested fields of the GraphQL type NoticeEdge. +// The GraphQL type's documentation follows. +// +// Pagination entry +type getNoticesNoticesNoticeConnectionEdgesNoticeEdge struct { + // Node instance + Node getNoticesNoticesNoticeConnectionEdgesNoticeEdgeNodeNotice `json:"node"` +} + +// GetNode returns getNoticesNoticesNoticeConnectionEdgesNoticeEdge.Node, and is useful for accessing the field via an interface. +func (v *getNoticesNoticesNoticeConnectionEdgesNoticeEdge) GetNode() getNoticesNoticesNoticeConnectionEdgesNoticeEdgeNodeNotice { + return v.Node +} + +// getNoticesNoticesNoticeConnectionEdgesNoticeEdgeNodeNotice includes the requested fields of the GraphQL type Notice. +// The GraphQL type's documentation follows. +// +// Informational statement that can be validated in the base layer blockchain +type getNoticesNoticesNoticeConnectionEdgesNoticeEdgeNodeNotice struct { + // Notice index within the context of the input that produced it + Index int `json:"index"` + // Notice data as a payload in Ethereum hex binary format, starting with '0x' + Payload string `json:"payload"` + // Proof object that allows this notice to be validated by the base layer blockchain + Proof getNoticesNoticesNoticeConnectionEdgesNoticeEdgeNodeNoticeProof `json:"proof"` + // Input whose processing produced the notice + Input getNoticesNoticesNoticeConnectionEdgesNoticeEdgeNodeNoticeInput `json:"input"` +} + +// GetIndex returns getNoticesNoticesNoticeConnectionEdgesNoticeEdgeNodeNotice.Index, and is useful for accessing the field via an interface. +func (v *getNoticesNoticesNoticeConnectionEdgesNoticeEdgeNodeNotice) GetIndex() int { return v.Index } + +// GetPayload returns getNoticesNoticesNoticeConnectionEdgesNoticeEdgeNodeNotice.Payload, and is useful for accessing the field via an interface. +func (v *getNoticesNoticesNoticeConnectionEdgesNoticeEdgeNodeNotice) GetPayload() string { + return v.Payload +} + +// GetProof returns getNoticesNoticesNoticeConnectionEdgesNoticeEdgeNodeNotice.Proof, and is useful for accessing the field via an interface. +func (v *getNoticesNoticesNoticeConnectionEdgesNoticeEdgeNodeNotice) GetProof() getNoticesNoticesNoticeConnectionEdgesNoticeEdgeNodeNoticeProof { + return v.Proof +} + +// GetInput returns getNoticesNoticesNoticeConnectionEdgesNoticeEdgeNodeNotice.Input, and is useful for accessing the field via an interface. +func (v *getNoticesNoticesNoticeConnectionEdgesNoticeEdgeNodeNotice) GetInput() getNoticesNoticesNoticeConnectionEdgesNoticeEdgeNodeNoticeInput { + return v.Input +} + +// getNoticesNoticesNoticeConnectionEdgesNoticeEdgeNodeNoticeInput includes the requested fields of the GraphQL type Input. +// The GraphQL type's documentation follows. +// +// Request submitted to the application to advance its state +type getNoticesNoticesNoticeConnectionEdgesNoticeEdgeNodeNoticeInput struct { + // Input index starting from genesis + Index int `json:"index"` +} + +// GetIndex returns getNoticesNoticesNoticeConnectionEdgesNoticeEdgeNodeNoticeInput.Index, and is useful for accessing the field via an interface. +func (v *getNoticesNoticesNoticeConnectionEdgesNoticeEdgeNodeNoticeInput) GetIndex() int { + return v.Index +} + +// getNoticesNoticesNoticeConnectionEdgesNoticeEdgeNodeNoticeProof includes the requested fields of the GraphQL type Proof. +// The GraphQL type's documentation follows. +// +// Data that can be used as proof to validate notices and execute vouchers on the base layer blockchain +type getNoticesNoticesNoticeConnectionEdgesNoticeEdgeNodeNoticeProof struct { + // Validity proof for an output + Validity getNoticesNoticesNoticeConnectionEdgesNoticeEdgeNodeNoticeProofValidityOutputValidityProof `json:"validity"` + // Data that allows the validity proof to be contextualized within submitted claims, given as a payload in Ethereum hex binary format, starting with '0x' + Context string `json:"context"` +} + +// GetValidity returns getNoticesNoticesNoticeConnectionEdgesNoticeEdgeNodeNoticeProof.Validity, and is useful for accessing the field via an interface. +func (v *getNoticesNoticesNoticeConnectionEdgesNoticeEdgeNodeNoticeProof) GetValidity() getNoticesNoticesNoticeConnectionEdgesNoticeEdgeNodeNoticeProofValidityOutputValidityProof { + return v.Validity +} + +// GetContext returns getNoticesNoticesNoticeConnectionEdgesNoticeEdgeNodeNoticeProof.Context, and is useful for accessing the field via an interface. +func (v *getNoticesNoticesNoticeConnectionEdgesNoticeEdgeNodeNoticeProof) GetContext() string { + return v.Context +} + +// getNoticesNoticesNoticeConnectionEdgesNoticeEdgeNodeNoticeProofValidityOutputValidityProof includes the requested fields of the GraphQL type OutputValidityProof. +// The GraphQL type's documentation follows. +// +// Validity proof for an output +type getNoticesNoticesNoticeConnectionEdgesNoticeEdgeNodeNoticeProofValidityOutputValidityProof struct { + // Local input index within the context of the related epoch + InputIndexWithinEpoch int `json:"inputIndexWithinEpoch"` + // Output index within the context of the input that produced it + OutputIndexWithinInput int `json:"outputIndexWithinInput"` + // Merkle root of all output hashes of the related input, given in Ethereum hex binary format (32 bytes), starting with '0x' + OutputHashesRootHash string `json:"outputHashesRootHash"` + // Merkle root of all voucher hashes of the related epoch, given in Ethereum hex binary format (32 bytes), starting with '0x' + VouchersEpochRootHash string `json:"vouchersEpochRootHash"` + // Merkle root of all notice hashes of the related epoch, given in Ethereum hex binary format (32 bytes), starting with '0x' + NoticesEpochRootHash string `json:"noticesEpochRootHash"` + // Hash of the machine state claimed for the related epoch, given in Ethereum hex binary format (32 bytes), starting with '0x' + MachineStateHash string `json:"machineStateHash"` + // Proof that this output hash is in the output-hashes merkle tree. This array of siblings is bottom-up ordered (from the leaf to the root). Each hash is given in Ethereum hex binary format (32 bytes), starting with '0x'. + OutputHashInOutputHashesSiblings []string `json:"outputHashInOutputHashesSiblings"` + // Proof that this output-hashes root hash is in epoch's output merkle tree. This array of siblings is bottom-up ordered (from the leaf to the root). Each hash is given in Ethereum hex binary format (32 bytes), starting with '0x'. + OutputHashesInEpochSiblings []string `json:"outputHashesInEpochSiblings"` +} + +// GetInputIndexWithinEpoch returns getNoticesNoticesNoticeConnectionEdgesNoticeEdgeNodeNoticeProofValidityOutputValidityProof.InputIndexWithinEpoch, and is useful for accessing the field via an interface. +func (v *getNoticesNoticesNoticeConnectionEdgesNoticeEdgeNodeNoticeProofValidityOutputValidityProof) GetInputIndexWithinEpoch() int { + return v.InputIndexWithinEpoch +} + +// GetOutputIndexWithinInput returns getNoticesNoticesNoticeConnectionEdgesNoticeEdgeNodeNoticeProofValidityOutputValidityProof.OutputIndexWithinInput, and is useful for accessing the field via an interface. +func (v *getNoticesNoticesNoticeConnectionEdgesNoticeEdgeNodeNoticeProofValidityOutputValidityProof) GetOutputIndexWithinInput() int { + return v.OutputIndexWithinInput +} + +// GetOutputHashesRootHash returns getNoticesNoticesNoticeConnectionEdgesNoticeEdgeNodeNoticeProofValidityOutputValidityProof.OutputHashesRootHash, and is useful for accessing the field via an interface. +func (v *getNoticesNoticesNoticeConnectionEdgesNoticeEdgeNodeNoticeProofValidityOutputValidityProof) GetOutputHashesRootHash() string { + return v.OutputHashesRootHash +} + +// GetVouchersEpochRootHash returns getNoticesNoticesNoticeConnectionEdgesNoticeEdgeNodeNoticeProofValidityOutputValidityProof.VouchersEpochRootHash, and is useful for accessing the field via an interface. +func (v *getNoticesNoticesNoticeConnectionEdgesNoticeEdgeNodeNoticeProofValidityOutputValidityProof) GetVouchersEpochRootHash() string { + return v.VouchersEpochRootHash +} + +// GetNoticesEpochRootHash returns getNoticesNoticesNoticeConnectionEdgesNoticeEdgeNodeNoticeProofValidityOutputValidityProof.NoticesEpochRootHash, and is useful for accessing the field via an interface. +func (v *getNoticesNoticesNoticeConnectionEdgesNoticeEdgeNodeNoticeProofValidityOutputValidityProof) GetNoticesEpochRootHash() string { + return v.NoticesEpochRootHash +} + +// GetMachineStateHash returns getNoticesNoticesNoticeConnectionEdgesNoticeEdgeNodeNoticeProofValidityOutputValidityProof.MachineStateHash, and is useful for accessing the field via an interface. +func (v *getNoticesNoticesNoticeConnectionEdgesNoticeEdgeNodeNoticeProofValidityOutputValidityProof) GetMachineStateHash() string { + return v.MachineStateHash +} + +// GetOutputHashInOutputHashesSiblings returns getNoticesNoticesNoticeConnectionEdgesNoticeEdgeNodeNoticeProofValidityOutputValidityProof.OutputHashInOutputHashesSiblings, and is useful for accessing the field via an interface. +func (v *getNoticesNoticesNoticeConnectionEdgesNoticeEdgeNodeNoticeProofValidityOutputValidityProof) GetOutputHashInOutputHashesSiblings() []string { + return v.OutputHashInOutputHashesSiblings +} + +// GetOutputHashesInEpochSiblings returns getNoticesNoticesNoticeConnectionEdgesNoticeEdgeNodeNoticeProofValidityOutputValidityProof.OutputHashesInEpochSiblings, and is useful for accessing the field via an interface. +func (v *getNoticesNoticesNoticeConnectionEdgesNoticeEdgeNodeNoticeProofValidityOutputValidityProof) GetOutputHashesInEpochSiblings() []string { + return v.OutputHashesInEpochSiblings +} + +// getNoticesResponse is returned by getNotices on success. +type getNoticesResponse struct { + // Get notices with support for pagination + Notices getNoticesNoticesNoticeConnection `json:"notices"` +} + +// GetNotices returns getNoticesResponse.Notices, and is useful for accessing the field via an interface. +func (v *getNoticesResponse) GetNotices() getNoticesNoticesNoticeConnection { return v.Notices } + // The query or mutation executed by getInput. const getInput_Operation = ` query getInput ($index: Int!) { @@ -327,6 +683,62 @@ func getInput( return &data, err } +// The query or mutation executed by getInputNotices. +const getInputNotices_Operation = ` +query getInputNotices ($inputIndex: Int!) { + input(index: $inputIndex) { + index + notices { + edges { + node { + index + payload + proof { + validity { + inputIndexWithinEpoch + outputIndexWithinInput + outputHashesRootHash + vouchersEpochRootHash + noticesEpochRootHash + machineStateHash + outputHashInOutputHashesSiblings + outputHashesInEpochSiblings + } + context + } + } + } + } + } +} +` + +func getInputNotices( + ctx context.Context, + client graphql.Client, + inputIndex int, +) (*getInputNoticesResponse, error) { + req := &graphql.Request{ + OpName: "getInputNotices", + Query: getInputNotices_Operation, + Variables: &__getInputNoticesInput{ + InputIndex: inputIndex, + }, + } + var err error + + var data getInputNoticesResponse + resp := &graphql.Response{Data: &data} + + err = client.MakeRequest( + ctx, + req, + resp, + ) + + return &data, err +} + // The query or mutation executed by getInputs. const getInputs_Operation = ` query getInputs { @@ -420,3 +832,55 @@ func getNotice( return &data, err } + +// The query or mutation executed by getNotices. +const getNotices_Operation = ` +query getNotices { + notices { + edges { + node { + index + payload + proof { + validity { + inputIndexWithinEpoch + outputIndexWithinInput + outputHashesRootHash + vouchersEpochRootHash + noticesEpochRootHash + machineStateHash + outputHashInOutputHashesSiblings + outputHashesInEpochSiblings + } + context + } + input { + index + } + } + } + } +} +` + +func getNotices( + ctx context.Context, + client graphql.Client, +) (*getNoticesResponse, error) { + req := &graphql.Request{ + OpName: "getNotices", + Query: getNotices_Operation, + } + var err error + + var data getNoticesResponse + resp := &graphql.Response{Data: &data} + + err = client.MakeRequest( + ctx, + req, + resp, + ) + + return &data, err +} diff --git a/pkg/readerclient/genqlient.yaml b/pkg/readerclient/genqlient.yaml index d07412414..4da8414f8 100644 --- a/pkg/readerclient/genqlient.yaml +++ b/pkg/readerclient/genqlient.yaml @@ -8,6 +8,8 @@ operations: - generate/input.graphql - generate/inputs.graphql - generate/notice.graphql +- generate/notices.graphql +- generate/input_notices.graphql generated: generated.go package: readerclient diff --git a/pkg/readerclient/notice.go b/pkg/readerclient/notice.go index ec212a1bc..a9663bba2 100644 --- a/pkg/readerclient/notice.go +++ b/pkg/readerclient/notice.go @@ -19,14 +19,14 @@ type Notice struct { // Notice data as a payload in Ethereum hex binary format, starting with '0x' Payload hexutil.Bytes `json:"payload"` // Proof object that allows this notice to be validated by the base layer blockchain - Proof Proof `json:"proof"` + Proof *Proof `json:"proof"` } func newNotice( index int, inputIndex int, payload string, - proof Proof, + proof *Proof, ) (*Notice, error) { convPayload, err := hexutil.Decode(payload) if err != nil { @@ -43,6 +43,95 @@ func newNotice( return ¬ice, err } +// Get multiple notices from graphql +// Uses notice index and input index as parameter on graphql query +func GetNotices( + ctx context.Context, + client graphql.Client, +) ([]Notice, error) { + + var notices []Notice + + resp, err := getNotices(ctx, client) + if err != nil { + return nil, err + } + + for _, edge := range resp.Notices.Edges { + + proof, err := newProof( + edge.Node.Proof.Validity.InputIndexWithinEpoch, + edge.Node.Proof.Validity.OutputIndexWithinInput, + edge.Node.Proof.Validity.OutputHashesRootHash, + edge.Node.Proof.Validity.VouchersEpochRootHash, + edge.Node.Proof.Validity.NoticesEpochRootHash, + edge.Node.Proof.Validity.MachineStateHash, + edge.Node.Proof.Validity.OutputHashInOutputHashesSiblings, + edge.Node.Proof.Validity.OutputHashesInEpochSiblings, + edge.Node.Proof.Context, + ) + if err != nil { + return nil, err + } + + notice, err := newNotice( + edge.Node.Index, + edge.Node.Input.Index, + edge.Node.Payload, + proof, + ) + + notices = append(notices, *notice) + } + + return notices, err +} + +// Get multiple notices from graphql +// Uses notice index and input index as parameter on graphql query +func GetInputNotices( + ctx context.Context, + client graphql.Client, + inputIndex int, +) ([]Notice, error) { + + var notices []Notice + + resp, err := getInputNotices(ctx, client, inputIndex) + if err != nil { + return nil, err + } + + for _, edge := range resp.Input.Notices.Edges { + + proof, err := newProof( + edge.Node.Proof.Validity.InputIndexWithinEpoch, + edge.Node.Proof.Validity.OutputIndexWithinInput, + edge.Node.Proof.Validity.OutputHashesRootHash, + edge.Node.Proof.Validity.VouchersEpochRootHash, + edge.Node.Proof.Validity.NoticesEpochRootHash, + edge.Node.Proof.Validity.MachineStateHash, + edge.Node.Proof.Validity.OutputHashInOutputHashesSiblings, + edge.Node.Proof.Validity.OutputHashesInEpochSiblings, + edge.Node.Proof.Context, + ) + if err != nil { + return nil, err + } + + notice, err := newNotice( + edge.Node.Index, + resp.Input.Index, + edge.Node.Payload, + proof, + ) + + notices = append(notices, *notice) + } + + return notices, err +} + // Get notice from graphql // Uses notice index and input index as parameter on graphql query func GetNotice( @@ -67,12 +156,15 @@ func GetNotice( resp.Notice.Proof.Validity.OutputHashesInEpochSiblings, resp.Notice.Proof.Context, ) + if err != nil { + return nil, err + } notice, err := newNotice( resp.Notice.Index, resp.Notice.Input.Index, resp.Notice.Payload, - *proof, + proof, ) return notice, err diff --git a/pkg/readerclient/proof.go b/pkg/readerclient/proof.go index d2aa1f81d..faf0bf53d 100644 --- a/pkg/readerclient/proof.go +++ b/pkg/readerclient/proof.go @@ -51,6 +51,12 @@ func newProof( outputHashOutputSiblings []hexutil.Bytes outputHashEpochSiblings []hexutil.Bytes ) + + // This tests if there's a proof, else it returns nil + if len(outputHashesRootHash) == 0 { + return nil, nil + } + outputHash, err := hexutil.Decode(outputHashesRootHash) if err != nil { return nil, fmt.Errorf("failed to decode OutputHashesRootHash to bytes: %v", err)