diff --git a/docs/predicate/asserta_1.md b/docs/predicate/asserta_1.md index 5e171cf5..659faddc 100644 --- a/docs/predicate/asserta_1.md +++ b/docs/predicate/asserta_1.md @@ -54,9 +54,9 @@ answer: results: - substitutions: - variable: X - expression: "john" - - variable: Y - expression: "pete" + expression: john + - variable: 'Y' + expression: pete ``` ### Only dynamic predicates can be asserted @@ -127,10 +127,10 @@ answer: results: - substitutions: - variable: X - expression: "john" + expression: john - substitutions: - variable: X - expression: "jane" + expression: jane ``` ### Shows a simple counter example diff --git a/docs/predicate/assertz_1.md b/docs/predicate/assertz_1.md index 805f3b61..a0e721bb 100644 --- a/docs/predicate/assertz_1.md +++ b/docs/predicate/assertz_1.md @@ -54,9 +54,9 @@ answer: results: - substitutions: - variable: X - expression: "john" - - variable: Y - expression: "pete" + expression: john + - variable: 'Y' + expression: pete ``` ### Only dynamic predicates can be asserted @@ -127,10 +127,10 @@ answer: results: - substitutions: - variable: X - expression: "jane" + expression: jane - substitutions: - variable: X - expression: "john" + expression: john ``` ### Add and remove items in an inventory diff --git a/docs/predicate/block_header_1.md b/docs/predicate/block_header_1.md new file mode 100644 index 00000000..d2a32b92 --- /dev/null +++ b/docs/predicate/block_header_1.md @@ -0,0 +1,189 @@ +--- +sidebar_position: 10 +--- +[//]: # (This file is auto-generated. Please do not modify it yourself.) + +# block_header/1 + +## Description + +`block_header/1` is a predicate which unifies the given term with the current block header. + +## Signature + +```text +block_header(?Header) is det +``` + +where: + +- Header is a Dict representing the current chain header at the time of the query. + +## Examples + +### Retrieve the header of the current block + +This scenario demonstrates how to retrieve the header of the current block and obtain some of its properties. + +The header of a block carries important information about the state of the blockchain, such as basic information (chain id, the height, +time, and height), the information about the last block, hashes, and the consensus info. + +The header is represented as a Prolog Dict, which is a collection of key-value pairs. + +Here are the steps of the scenario: + +- **Given** a block with the following header: + +``` yaml +app_hash: Q0P6b2hoSUbmpCE6o6Dme4H4FBWqdcpqo89DrpBYSHQ= +chain_id: axone-localnet +height: 33 +next_validators_hash: EIQFMnCDepfXD2e3OeL1QoEfmu6BZQbKR500Wkl4gK0= +proposer_address: yz7PSKMWniQlQWMd7LskBABgDKQ= +time: "2024-11-22T21:22:04.676789Z" +``` + +- **Given** the query: + +``` prolog +block_header(Header). +``` + +- **When** the query is run +- **Then** the answer we get is: + +``` yaml +height: 33 +gas_used: 3975 +answer: + has_more: false + variables: ["Header"] + results: + - substitutions: + - variable: Header + expression: >- + header{app_hash:[67,67,250,111,104,104,73,70,230,164,33,58,163,160,230,123,129,248,20,21,170,117,202,106,163,207,67,174,144,88,72,116],chain_id:'axone-localnet',consensus_hash:[],data_hash:[],evidence_hash:[],height:33,last_block_id:block_id{hash:[],part_set_header:part_set_header{hash:[],total:0}},last_commit_hash:[],last_results_hash:[],next_validators_hash:[16,132,5,50,112,131,122,151,215,15,103,183,57,226,245,66,129,31,154,238,129,101,6,202,71,157,52,90,73,120,128,173],proposer_address:[203,62,207,72,163,22,158,36,37,65,99,29,236,187,36,4,0,96,12,164],time:1732310524,validators_hash:[],version:consensus{app:0,block:0}} +``` + +### Retrieve the block height of the current block + +This scenario demonstrates how to retrieve the block height of the current block. + +Here are the steps of the scenario: + +- **Given** a block with the following header: + +``` yaml +height: 100 +``` + +- **Given** the program: + +``` prolog +height(Height) :- + block_header(Header), + Height = Header.height. +``` + +- **Given** the query: + +``` prolog +height(Height). +``` + +- **When** the query is run +- **Then** the answer we get is: + +``` yaml +height: 100 +gas_used: 3978 +answer: + has_more: false + variables: ["Height"] + results: + - substitutions: + - variable: Height + expression: "100" +``` + +### Retrieve the block time of the current block + +This scenario demonstrates how to retrieve the block time of the current block. + +Here are the steps of the scenario: + +- **Given** a block with the following header: + +``` yaml +time: 2024-03-04T11:03:36.000Z +``` + +- **Given** the program: + +``` prolog +time(Time) :- + block_header(Header), + Time = Header.time. +``` + +- **Given** the query: + +``` prolog +time(Time). +``` + +- **When** the query is run +- **Then** the answer we get is: + +``` yaml +height: 42 +gas_used: 3978 +answer: + has_more: false + variables: ["Time"] + results: + - substitutions: + - variable: Time + expression: "1709550216" +``` + +### Evaluate a condition based on block time and height + +This scenario demonstrates how to evaluate a condition that depends on both the block time and block height. +Specifically, it checks whether the block time is greater than 1709550216 seconds (Monday 4 March 2024 11:03:36 GMT) +or the block height is greater than 42. + +Here are the steps of the scenario: + +- **Given** a block with the following header: + +``` yaml +time: 2024-03-04T11:03:37.000Z +``` + +- **Given** the program: + +``` prolog +evaluate :- + block_header(Header), + (Header.time > 1709550216; Header.height > 42), + !. +``` + +- **Given** the query: + +``` prolog +evaluate. +``` + +- **When** the query is run +- **Then** the answer we get is: + +``` yaml +height: 42 +gas_used: 3981 +answer: + has_more: false + results: + - substitutions: +``` diff --git a/docs/predicate/block_height_1.md b/docs/predicate/block_height_1.md index 5b52afc1..7a480034 100644 --- a/docs/predicate/block_height_1.md +++ b/docs/predicate/block_height_1.md @@ -1,5 +1,5 @@ --- -sidebar_position: 10 +sidebar_position: 11 --- [//]: # (This file is auto-generated. Please do not modify it yourself.) @@ -19,72 +19,4 @@ where: - Height represents the current chain height at the time of the query. -## Examples - -### Retrieve the block height of the current block - -This scenario demonstrates how to retrieve the block height of the current block. - -Here are the steps of the scenario: - -- **Given** a block with the following header: - -| key | value | -| --- | ----- | -| Height | 100 | - -- **Given** the query: - -``` prolog -block_height(Height). -``` - -- **When** the query is run -- **Then** the answer we get is: - -``` yaml -height: 100 -gas_used: 3975 -answer: - has_more: false - variables: ["Height"] - results: - - substitutions: - - variable: Height - expression: "100" -``` - -### Check that the block height is greater than a certain value - -This scenario demonstrates how to check that the block height is greater than 100. This predicate is useful for -governance which requires a certain block height to be reached before a certain action is taken. - -Here are the steps of the scenario: - -- **Given** a block with the following header: - -| key | value | -| --- | ----- | -| Height | 101 | - -- **Given** the query: - -``` prolog -block_height(Height), -Height > 100. -``` - -- **When** the query is run -- **Then** the answer we get is: - -``` yaml -height: 101 -gas_used: 3976 -answer: - has_more: false - variables: ["Height"] - results: - - substitutions: - - variable: Height - expression: "101" -``` +Deprecated: Use the \`block\_header/1\` predicate instead. diff --git a/docs/predicate/block_time_1.md b/docs/predicate/block_time_1.md index 2e17539a..8b81831c 100644 --- a/docs/predicate/block_time_1.md +++ b/docs/predicate/block_time_1.md @@ -1,5 +1,5 @@ --- -sidebar_position: 11 +sidebar_position: 12 --- [//]: # (This file is auto-generated. Please do not modify it yourself.) @@ -19,73 +19,4 @@ where: - Time represents the current chain time at the time of the query. -## Examples - -### Retrieve the block time of the current block - -This scenario demonstrates how to retrieve the block time of the current block. - -Here are the steps of the scenario: - -- **Given** a block with the following header: - -| key | value | -| --- | ----- | -| Time | 1709550216 | - -- **Given** the query: - -``` prolog -block_time(Time). -``` - -- **When** the query is run -- **Then** the answer we get is: - -``` yaml -height: 42 -gas_used: 3975 -answer: - has_more: false - variables: ["Time"] - results: - - substitutions: - - variable: Time - expression: "1709550216" -``` - -### Check that the block time is greater than a certain time - -This scenario demonstrates how to check that the block time is greater than 1709550216 seconds (Monday 4 March 2024 11:03:36 GMT) -using the `block_time/1` predicate. This predicate is useful for governance which requires a certain block time to be -reached before a certain action is taken. - -Here are the steps of the scenario: - -- **Given** a block with the following header: - -| key | value | -| --- | ----- | -| Time | 1709550217 | - -- **Given** the query: - -``` prolog -block_time(Time), -Time > 1709550216. -``` - -- **When** the query is run -- **Then** the answer we get is: - -``` yaml -height: 42 -gas_used: 3976 -answer: - has_more: false - variables: ["Time"] - results: - - substitutions: - - variable: Time - expression: "1709550217" -``` +Deprecated: Use the \`block\_header/1\` predicate instead. diff --git a/docs/predicate/chain_id_1.md b/docs/predicate/chain_id_1.md index 9830755f..46b66a05 100644 --- a/docs/predicate/chain_id_1.md +++ b/docs/predicate/chain_id_1.md @@ -1,5 +1,5 @@ --- -sidebar_position: 12 +sidebar_position: 13 --- [//]: # (This file is auto-generated. Please do not modify it yourself.) @@ -19,9 +19,4 @@ where: - ID represents the current chain ID at the time of the query. -## Examples - -```text -# Query the current chain ID. -- chain_id(ID). -``` +Deprecated: Use the \`block\_header/1\` predicate instead. diff --git a/docs/predicate/consult_1.md b/docs/predicate/consult_1.md index 724734ad..14f342c6 100644 --- a/docs/predicate/consult_1.md +++ b/docs/predicate/consult_1.md @@ -1,5 +1,5 @@ --- -sidebar_position: 13 +sidebar_position: 14 --- [//]: # (This file is auto-generated. Please do not modify it yourself.) diff --git a/docs/predicate/crypto_data_hash_3.md b/docs/predicate/crypto_data_hash_3.md index d39bbfd4..645a3b81 100644 --- a/docs/predicate/crypto_data_hash_3.md +++ b/docs/predicate/crypto_data_hash_3.md @@ -1,5 +1,5 @@ --- -sidebar_position: 14 +sidebar_position: 15 --- [//]: # (This file is auto-generated. Please do not modify it yourself.) diff --git a/docs/predicate/current_output_1.md b/docs/predicate/current_output_1.md index c375ed7a..b9d3a38c 100644 --- a/docs/predicate/current_output_1.md +++ b/docs/predicate/current_output_1.md @@ -1,5 +1,5 @@ --- -sidebar_position: 15 +sidebar_position: 16 --- [//]: # (This file is auto-generated. Please do not modify it yourself.) diff --git a/docs/predicate/did_components_2.md b/docs/predicate/did_components_2.md index 6c8f26c6..8a572afa 100644 --- a/docs/predicate/did_components_2.md +++ b/docs/predicate/did_components_2.md @@ -1,5 +1,5 @@ --- -sidebar_position: 16 +sidebar_position: 17 --- [//]: # (This file is auto-generated. Please do not modify it yourself.) diff --git a/docs/predicate/ecdsa_verify_4.md b/docs/predicate/ecdsa_verify_4.md index b3317cd7..39bd6270 100644 --- a/docs/predicate/ecdsa_verify_4.md +++ b/docs/predicate/ecdsa_verify_4.md @@ -1,5 +1,5 @@ --- -sidebar_position: 17 +sidebar_position: 18 --- [//]: # (This file is auto-generated. Please do not modify it yourself.) diff --git a/docs/predicate/eddsa_verify_4.md b/docs/predicate/eddsa_verify_4.md index 09b053f8..6c668201 100644 --- a/docs/predicate/eddsa_verify_4.md +++ b/docs/predicate/eddsa_verify_4.md @@ -1,5 +1,5 @@ --- -sidebar_position: 18 +sidebar_position: 19 --- [//]: # (This file is auto-generated. Please do not modify it yourself.) diff --git a/docs/predicate/hex_bytes_2.md b/docs/predicate/hex_bytes_2.md index 56423e82..7762bf5a 100644 --- a/docs/predicate/hex_bytes_2.md +++ b/docs/predicate/hex_bytes_2.md @@ -1,5 +1,5 @@ --- -sidebar_position: 19 +sidebar_position: 20 --- [//]: # (This file is auto-generated. Please do not modify it yourself.) diff --git a/docs/predicate/json_prolog_2.md b/docs/predicate/json_prolog_2.md index edc3a7d7..27b5d5f4 100644 --- a/docs/predicate/json_prolog_2.md +++ b/docs/predicate/json_prolog_2.md @@ -1,5 +1,5 @@ --- -sidebar_position: 20 +sidebar_position: 21 --- [//]: # (This file is auto-generated. Please do not modify it yourself.) diff --git a/docs/predicate/json_read_2.md b/docs/predicate/json_read_2.md index 8041acf1..3fdf10ee 100644 --- a/docs/predicate/json_read_2.md +++ b/docs/predicate/json_read_2.md @@ -1,5 +1,5 @@ --- -sidebar_position: 21 +sidebar_position: 22 --- [//]: # (This file is auto-generated. Please do not modify it yourself.) diff --git a/docs/predicate/json_write_2.md b/docs/predicate/json_write_2.md index 5598e590..b893e0fc 100644 --- a/docs/predicate/json_write_2.md +++ b/docs/predicate/json_write_2.md @@ -1,5 +1,5 @@ --- -sidebar_position: 22 +sidebar_position: 23 --- [//]: # (This file is auto-generated. Please do not modify it yourself.) diff --git a/docs/predicate/open_3.md b/docs/predicate/open_3.md index f6676600..778a39b3 100644 --- a/docs/predicate/open_3.md +++ b/docs/predicate/open_3.md @@ -1,5 +1,5 @@ --- -sidebar_position: 24 +sidebar_position: 25 --- [//]: # (This file is auto-generated. Please do not modify it yourself.) diff --git a/docs/predicate/open_4.md b/docs/predicate/open_4.md index c351b2eb..dbefa51a 100644 --- a/docs/predicate/open_4.md +++ b/docs/predicate/open_4.md @@ -1,5 +1,5 @@ --- -sidebar_position: 23 +sidebar_position: 24 --- [//]: # (This file is auto-generated. Please do not modify it yourself.) diff --git a/docs/predicate/read_string_3.md b/docs/predicate/read_string_3.md index a0db1836..4499960f 100644 --- a/docs/predicate/read_string_3.md +++ b/docs/predicate/read_string_3.md @@ -1,5 +1,5 @@ --- -sidebar_position: 25 +sidebar_position: 26 --- [//]: # (This file is auto-generated. Please do not modify it yourself.) diff --git a/docs/predicate/read_term_3.md b/docs/predicate/read_term_3.md index 43f969b2..ca53a8be 100644 --- a/docs/predicate/read_term_3.md +++ b/docs/predicate/read_term_3.md @@ -1,5 +1,5 @@ --- -sidebar_position: 26 +sidebar_position: 27 --- [//]: # (This file is auto-generated. Please do not modify it yourself.) diff --git a/docs/predicate/retract_1.md b/docs/predicate/retract_1.md index 1d776cc1..e78cf6b8 100644 --- a/docs/predicate/retract_1.md +++ b/docs/predicate/retract_1.md @@ -1,5 +1,5 @@ --- -sidebar_position: 27 +sidebar_position: 28 --- [//]: # (This file is auto-generated. Please do not modify it yourself.) diff --git a/docs/predicate/source_file_1.md b/docs/predicate/source_file_1.md index 32e6cf88..49460027 100644 --- a/docs/predicate/source_file_1.md +++ b/docs/predicate/source_file_1.md @@ -1,5 +1,5 @@ --- -sidebar_position: 28 +sidebar_position: 29 --- [//]: # (This file is auto-generated. Please do not modify it yourself.) diff --git a/docs/predicate/string_bytes_3.md b/docs/predicate/string_bytes_3.md index cee492a1..3370c600 100644 --- a/docs/predicate/string_bytes_3.md +++ b/docs/predicate/string_bytes_3.md @@ -1,5 +1,5 @@ --- -sidebar_position: 29 +sidebar_position: 30 --- [//]: # (This file is auto-generated. Please do not modify it yourself.) diff --git a/docs/predicate/term_to_atom_2.md b/docs/predicate/term_to_atom_2.md index a83a037f..ca76db69 100644 --- a/docs/predicate/term_to_atom_2.md +++ b/docs/predicate/term_to_atom_2.md @@ -1,5 +1,5 @@ --- -sidebar_position: 30 +sidebar_position: 31 --- [//]: # (This file is auto-generated. Please do not modify it yourself.) diff --git a/docs/predicate/uri_encoded_3.md b/docs/predicate/uri_encoded_3.md index 2d2798f1..4f82d9d6 100644 --- a/docs/predicate/uri_encoded_3.md +++ b/docs/predicate/uri_encoded_3.md @@ -1,5 +1,5 @@ --- -sidebar_position: 31 +sidebar_position: 32 --- [//]: # (This file is auto-generated. Please do not modify it yourself.) diff --git a/docs/predicate/write_term_3.md b/docs/predicate/write_term_3.md index 721cbb25..dbfcc3a9 100644 --- a/docs/predicate/write_term_3.md +++ b/docs/predicate/write_term_3.md @@ -1,5 +1,5 @@ --- -sidebar_position: 32 +sidebar_position: 33 --- [//]: # (This file is auto-generated. Please do not modify it yourself.) diff --git a/go.mod b/go.mod index be008226..69f65c63 100644 --- a/go.mod +++ b/go.mod @@ -21,7 +21,7 @@ require ( dario.cat/mergo v1.0.1 github.com/CosmWasm/wasmd v0.53.0 github.com/Masterminds/sprig/v3 v3.3.0 - github.com/axone-protocol/prolog v1.0.1-0.20241007111431-c4c18d4393b9 + github.com/axone-protocol/prolog v1.0.1-0.20241123121322-d4ffd777d1cd github.com/cometbft/cometbft v0.38.15 github.com/cosmos/cosmos-db v1.0.2 github.com/cosmos/cosmos-proto v1.0.0-beta.5 @@ -34,6 +34,7 @@ require ( github.com/cucumber/godog v0.15.0 github.com/cucumber/messages/go/v21 v21.0.1 github.com/dustinxie/ecc v0.0.0-20210511000915-959544187564 + github.com/goccy/go-yaml v1.9.7 github.com/golang/protobuf v1.5.4 github.com/grpc-ecosystem/grpc-gateway v1.16.0 github.com/hashicorp/go-metrics v0.5.3 @@ -61,7 +62,6 @@ require ( google.golang.org/genproto/googleapis/api v0.0.0-20240903143218-8af14fe29dc1 google.golang.org/grpc v1.68.0 google.golang.org/protobuf v1.35.2 - gopkg.in/yaml.v3 v3.0.1 gotest.tools/v3 v3.5.1 sigs.k8s.io/yaml v1.4.0 ) @@ -305,12 +305,14 @@ require ( golang.org/x/text v0.20.0 // indirect golang.org/x/time v0.5.0 // indirect golang.org/x/tools v0.22.0 // indirect + golang.org/x/xerrors v0.0.0-20231012003039-104605ab7028 // indirect google.golang.org/api v0.171.0 // indirect google.golang.org/genproto v0.0.0-20240227224415-6ceb2ff114de // indirect google.golang.org/genproto/googleapis/rpc v0.0.0-20240930140551-af27646dc61f // indirect gopkg.in/ini.v1 v1.67.0 // indirect gopkg.in/warnings.v0 v0.1.2 // indirect gopkg.in/yaml.v2 v2.4.0 // indirect + gopkg.in/yaml.v3 v3.0.1 // indirect mvdan.cc/xurls/v2 v2.2.0 // indirect nhooyr.io/websocket v1.8.6 // indirect pgregory.net/rapid v1.1.0 // indirect diff --git a/go.sum b/go.sum index cdcb6722..1621787b 100644 --- a/go.sum +++ b/go.sum @@ -289,8 +289,10 @@ github.com/aws/aws-sdk-go v1.44.122/go.mod h1:y4AeaBuwd2Lk+GepC1E9v0qOiTws0MIWAX github.com/aws/aws-sdk-go v1.44.224 h1:09CiaaF35nRmxrzWZ2uRq5v6Ghg/d2RiPjZnSgtt+RQ= github.com/aws/aws-sdk-go v1.44.224/go.mod h1:aVsgQcEevwlmQ7qHE9I3h+dtQgpqhFB+i8Phjh7fkwI= github.com/aws/aws-sdk-go-v2 v0.18.0/go.mod h1:JWVYvqSMppoMJC0x5wdwiImzgXTI9FuZwxzkQq9wy+g= -github.com/axone-protocol/prolog v1.0.1-0.20241007111431-c4c18d4393b9 h1:jn+ld5dI6Jfc0E9H3nELeU+CdieIzsbT+agfyyOZNuc= -github.com/axone-protocol/prolog v1.0.1-0.20241007111431-c4c18d4393b9/go.mod h1:6jc/PgoaC+m8Zsews7MQwxlcE1nLyu28peJb4qEcve8= +github.com/axone-protocol/prolog v1.0.1-0.20241120160414-7be6699dffe3 h1:iFAq3IER5fwxg9//SIer2yvONGmaS5OWhoTZM5yjJbQ= +github.com/axone-protocol/prolog v1.0.1-0.20241120160414-7be6699dffe3/go.mod h1:ZLTfrR1+oVoiSkfkI/QttzYoWWNBYVwt/TBv+MJ8mqA= +github.com/axone-protocol/prolog v1.0.1-0.20241123121322-d4ffd777d1cd h1:C41uQli3nMy+74Gy7aptG9HOhiiNIrmY5/9EJMy0Qa0= +github.com/axone-protocol/prolog v1.0.1-0.20241123121322-d4ffd777d1cd/go.mod h1:ZLTfrR1+oVoiSkfkI/QttzYoWWNBYVwt/TBv+MJ8mqA= github.com/bahlo/generic-list-go v0.2.0 h1:5sz/EEAK+ls5wF+NeqDpk5+iNdMDXrh3z3nPnH1Wvgk= github.com/bahlo/generic-list-go v0.2.0/go.mod h1:2KvAjgMlE5NNynlg/5iLrrCCZ2+5xWbdbCW3pNTGyYg= github.com/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA= @@ -576,11 +578,15 @@ github.com/go-logr/logr v1.4.1 h1:pKouT5E8xu9zeFC39JXRDukb6JFQPXM5p5I91188VAQ= github.com/go-logr/logr v1.4.1/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= +github.com/go-playground/assert/v2 v2.0.1/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4= github.com/go-playground/assert/v2 v2.2.0/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4= +github.com/go-playground/locales v0.13.0/go.mod h1:taPMhCMXrRLJO55olJkUXHZBHCxTMfnGwq/HNwmWNS8= github.com/go-playground/locales v0.14.1 h1:EWaQ/wswjilfKLTECiXz7Rh+3BjFhfDFKv/oXslEjJA= github.com/go-playground/locales v0.14.1/go.mod h1:hxrqLVvrK65+Rwrd5Fc6F2O76J/NuW9t0sjnWqG1slY= +github.com/go-playground/universal-translator v0.17.0/go.mod h1:UkSxE5sNxxRwHyU+Scu5vgOQjsIJAF8j9muTVoKLVtA= github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJnYK9S473LQFuzCbDbfSFY= github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY= +github.com/go-playground/validator/v10 v10.4.1/go.mod h1:nlOn6nFhuKACm19sB/8EGNn9GlaMV7XkbRSipzJ0Ii4= github.com/go-playground/validator/v10 v10.11.2 h1:q3SHpufmypg+erIExEKUmsgmhDTyhcJ38oeKGACXohU= github.com/go-playground/validator/v10 v10.11.2/go.mod h1:NieE624vt4SCTJtD87arVLvdmjPAeV8BQlHtMnw9D7s= github.com/go-sql-driver/mysql v1.4.0/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w= @@ -596,6 +602,8 @@ github.com/gobwas/ws v1.0.2/go.mod h1:szmBTxLgaFppYjEmNtny/v3w89xOydFnnZMcgRRu/E github.com/goccy/go-json v0.10.0/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I= github.com/goccy/go-json v0.10.3 h1:KZ5WoDbxAIgm2HNbYckL0se1fHD6rz5j4ywS6ebzDqA= github.com/goccy/go-json v0.10.3/go.mod h1:oq7eo15ShAhp70Anwd5lgX2pLfOS3QCiwU/PULtXL6M= +github.com/goccy/go-yaml v1.9.7 h1:D/Vx+JITklB1ugSkncB4BNR67M3X6AKs9+rqVeo3ddw= +github.com/goccy/go-yaml v1.9.7/go.mod h1:JubOolP3gh0HpiBc4BLRD4YmjEjHAmIIB2aaXKkTfoE= github.com/godbus/dbus v0.0.0-20190726142602-4481cbc300e2 h1:ZpnhV/YsD2/4cESfV5+Hoeu/iUR3ruzNvZ+yQfO03a0= github.com/godbus/dbus v0.0.0-20190726142602-4481cbc300e2/go.mod h1:bBOAhwG1umN6/6ZUMtDFBMQR8jRg9O75tm9K00oMsK4= github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= @@ -910,6 +918,7 @@ github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc= github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw= +github.com/leodido/go-urn v1.2.0/go.mod h1:+8+nEpDfqqsY+g338gtMEUOtuK+4dEMhiQEgxpxOKII= github.com/leodido/go-urn v1.2.1 h1:BqpAaACuzVSgi/VLzGZIobT2z4v53pjosyNd9Yv6n/w= github.com/leodido/go-urn v1.2.1/go.mod h1:zt4jvISO2HfUBqxjfIshjdMTYS56ZS/qv49ictyFfxY= github.com/lestrrat-go/blackmagic v1.0.2 h1:Cg2gVSc9h7sz9NOByczrbUvLopQmXrfFx//N+AkAr5k= @@ -1595,6 +1604,7 @@ golang.org/x/sys v0.0.0-20220227234510-4e6760a101f9/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20220310020820-b874c991c1a5/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220315194320-039c03cc5b86/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220328115105-d36c6a25d886/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220406163625-3f8b81556e12/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220412211240-33da011f77ad/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220502124256-b6088ccd6cba/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220503163025-988cb79eb6c6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= diff --git a/x/logic/interpreter/registry.go b/x/logic/interpreter/registry.go index 0d8cf95f..105e7dda 100644 --- a/x/logic/interpreter/registry.go +++ b/x/logic/interpreter/registry.go @@ -101,9 +101,11 @@ var registry = orderedmap.New[string, any]( {Key: "nth0/3", Value: engine.Nth0}, {Key: "nth1/3", Value: engine.Nth1}, {Key: "call_nth/2", Value: engine.CallNth}, - {Key: "chain_id/1", Value: predicate.ChainID}, - {Key: "block_height/1", Value: predicate.BlockHeight}, - {Key: "block_time/1", Value: predicate.BlockTime}, + {Key: "./3", Value: engine.Op3}, + {Key: "block_header/1", Value: predicate.BlockHeader}, + {Key: "chain_id/1", Value: predicate.ChainID}, //nolint:staticcheck // Deprecated but still exposed for compatibility. + {Key: "block_height/1", Value: predicate.BlockHeight}, //nolint:staticcheck // Deprecated but still exposed for compatibility. + {Key: "block_time/1", Value: predicate.BlockTime}, //nolint:staticcheck // Deprecated but still exposed for compatibility. {Key: "bank_balances/2", Value: predicate.BankBalances}, {Key: "bank_spendable_balances/2", Value: predicate.BankSpendableBalances}, {Key: "bank_locked_balances/2", Value: predicate.BankLockedBalances}, diff --git a/x/logic/keeper/features/block_height_1.feature b/x/logic/keeper/features/block_height_1.feature deleted file mode 100644 index c179cc32..00000000 --- a/x/logic/keeper/features/block_height_1.feature +++ /dev/null @@ -1,54 +0,0 @@ -Feature: block_height/1 - This feature is to test the block_height/2 predicate. - - @great_for_documentation - Scenario: Retrieve the block height of the current block. - This scenario demonstrates how to retrieve the block height of the current block. - - Given a block with the following header: - | Height | 100 | - - Given the query: - """ prolog - block_height(Height). - """ - When the query is run - Then the answer we get is: - """ yaml - height: 100 - gas_used: 3975 - answer: - has_more: false - variables: ["Height"] - results: - - substitutions: - - variable: Height - expression: "100" - """ - - @great_for_documentation - Scenario: Check that the block height is greater than a certain value. - This scenario demonstrates how to check that the block height is greater than 100. This predicate is useful for - governance which requires a certain block height to be reached before a certain action is taken. - - Given a block with the following header: - | Height | 101 | - - Given the query: - """ prolog - block_height(Height), - Height > 100. - """ - When the query is run - Then the answer we get is: - """ yaml - height: 101 - gas_used: 3976 - answer: - has_more: false - variables: ["Height"] - results: - - substitutions: - - variable: Height - expression: "101" - """ diff --git a/x/logic/keeper/features/block_time_1.feature b/x/logic/keeper/features/block_time_1.feature deleted file mode 100644 index dab2febf..00000000 --- a/x/logic/keeper/features/block_time_1.feature +++ /dev/null @@ -1,55 +0,0 @@ -Feature: block_time/1 - This feature is to test the block_time/2 predicate. - - @great_for_documentation - Scenario: Retrieve the block time of the current block. - This scenario demonstrates how to retrieve the block time of the current block. - - Given a block with the following header: - | Time | 1709550216 | - - Given the query: - """ prolog - block_time(Time). - """ - When the query is run - Then the answer we get is: - """ yaml - height: 42 - gas_used: 3975 - answer: - has_more: false - variables: ["Time"] - results: - - substitutions: - - variable: Time - expression: "1709550216" - """ - - @great_for_documentation - Scenario: Check that the block time is greater than a certain time. - This scenario demonstrates how to check that the block time is greater than 1709550216 seconds (Monday 4 March 2024 11:03:36 GMT) - using the `block_time/1` predicate. This predicate is useful for governance which requires a certain block time to be - reached before a certain action is taken. - - Given a block with the following header: - | Time | 1709550217 | - - Given the query: - """ prolog - block_time(Time), - Time > 1709550216. - """ - When the query is run - Then the answer we get is: - """ yaml - height: 42 - gas_used: 3976 - answer: - has_more: false - variables: ["Time"] - results: - - substitutions: - - variable: Time - expression: "1709550217" - """ diff --git a/x/logic/predicate/block.go b/x/logic/predicate/block.go index e82092e0..88162b01 100644 --- a/x/logic/predicate/block.go +++ b/x/logic/predicate/block.go @@ -17,6 +17,8 @@ import ( // where: // // - Height represents the current chain height at the time of the query. +// +// Deprecated: Use the `block_header/1` predicate instead. func BlockHeight(vm *engine.VM, height engine.Term, cont engine.Cont, env *engine.Env) *engine.Promise { return engine.Delay(func(ctx context.Context) *engine.Promise { sdkContext, err := prolog.UnwrapSDKContext(ctx, env) @@ -36,6 +38,8 @@ func BlockHeight(vm *engine.VM, height engine.Term, cont engine.Cont, env *engin // // where: // - Time represents the current chain time at the time of the query. +// +// Deprecated: Use the `block_header/1` predicate instead. func BlockTime(vm *engine.VM, time engine.Term, cont engine.Cont, env *engine.Env) *engine.Promise { return engine.Delay(func(ctx context.Context) *engine.Promise { sdkContext, err := prolog.UnwrapSDKContext(ctx, env) diff --git a/x/logic/predicate/chain.go b/x/logic/predicate/chain.go index 0434343f..dc3dce49 100644 --- a/x/logic/predicate/chain.go +++ b/x/logic/predicate/chain.go @@ -5,9 +5,100 @@ import ( "github.com/axone-protocol/prolog/engine" + cmtproto "github.com/cometbft/cometbft/proto/tendermint/types" + "github.com/cometbft/cometbft/proto/tendermint/version" + "github.com/axone-protocol/axoned/v10/x/logic/prolog" ) +// BlockHeader is a predicate which unifies the given term with the current block header. +// +// # Signature +// +// block_header(?Header) is det +// +// where: +// +// - Header is a Dict representing the current chain header at the time of the query. +func BlockHeader(vm *engine.VM, header engine.Term, cont engine.Cont, env *engine.Env) *engine.Promise { + return engine.Delay(func(ctx context.Context) *engine.Promise { + sdkContext, err := prolog.UnwrapSDKContext(ctx, env) + if err != nil { + return engine.Error(err) + } + + headerDict, err := blockHeaderToTerm(sdkContext.BlockHeader()) + if err != nil { + return engine.Error(err) + } + + return engine.Unify(vm, headerDict, header, cont, env) + }) +} + +func blockHeaderToTerm(header cmtproto.Header) (engine.Term, error) { + version, err := consensusToTerm(header.Version) + if err != nil { + return nil, err + } + + lastBlockID, err := blockIDToTerm(header.LastBlockId) + if err != nil { + return nil, err + } + + return engine.NewDict( + []engine.Term{ + engine.NewAtom("header"), + engine.NewAtom("version"), version, + engine.NewAtom("chain_id"), engine.NewAtom(header.ChainID), + engine.NewAtom("height"), engine.Integer(header.Height), + engine.NewAtom("time"), engine.Integer(header.Time.Unix()), + engine.NewAtom("last_block_id"), lastBlockID, + engine.NewAtom("last_commit_hash"), prolog.BytesToByteListTerm(header.LastCommitHash), + engine.NewAtom("data_hash"), prolog.BytesToByteListTerm(header.DataHash), + engine.NewAtom("validators_hash"), prolog.BytesToByteListTerm(header.ValidatorsHash), + engine.NewAtom("next_validators_hash"), prolog.BytesToByteListTerm(header.NextValidatorsHash), + engine.NewAtom("consensus_hash"), prolog.BytesToByteListTerm(header.ConsensusHash), + engine.NewAtom("app_hash"), prolog.BytesToByteListTerm(header.AppHash), + engine.NewAtom("last_results_hash"), prolog.BytesToByteListTerm(header.LastResultsHash), + engine.NewAtom("evidence_hash"), prolog.BytesToByteListTerm(header.EvidenceHash), + engine.NewAtom("proposer_address"), prolog.BytesToByteListTerm(header.ProposerAddress), + }, + ) +} + +func partSetHeaderToTerm(partSetHeader cmtproto.PartSetHeader) (engine.Dict, error) { + return engine.NewDict( + []engine.Term{ + engine.NewAtom("part_set_header"), + engine.NewAtom("total"), engine.Integer(partSetHeader.Total), + engine.NewAtom("hash"), prolog.BytesToByteListTerm(partSetHeader.Hash), + }) +} + +func consensusToTerm(consensus version.Consensus) (engine.Dict, error) { + return engine.NewDict([]engine.Term{ + engine.NewAtom("consensus"), + engine.NewAtom("block"), engine.Integer(consensus.Block), //nolint:gosec // disable G115 as it's unlikely to be a problem + engine.NewAtom("app"), engine.Integer(consensus.App), //nolint:gosec // disable G115 as it's unlikely to be a problem + }) +} + +func blockIDToTerm(blockID cmtproto.BlockID) (engine.Dict, error) { + partSetHeader, err := partSetHeaderToTerm(blockID.PartSetHeader) + if err != nil { + return nil, err + } + + return engine.NewDict( + []engine.Term{ + engine.NewAtom("block_id"), + engine.NewAtom("hash"), prolog.BytesToByteListTerm(blockID.Hash), + engine.NewAtom("part_set_header"), partSetHeader, + }) +} + // ChainID is a predicate which unifies the given term with the current chain ID. The signature is: // // The signature is as follows: @@ -17,10 +108,7 @@ import ( // where: // - ID represents the current chain ID at the time of the query. // -// # Examples: -// -// # Query the current chain ID. -// - chain_id(ID). +// Deprecated: Use the `block_header/1` predicate instead. func ChainID(vm *engine.VM, chainID engine.Term, cont engine.Cont, env *engine.Env) *engine.Promise { return engine.Delay(func(ctx context.Context) *engine.Promise { sdkContext, err := prolog.UnwrapSDKContext(ctx, env) diff --git a/x/logic/keeper/features/asserta_1.feature b/x/logic/predicate/features/asserta_1.feature similarity index 96% rename from x/logic/keeper/features/asserta_1.feature rename to x/logic/predicate/features/asserta_1.feature index 6c8cda51..8eef67d9 100644 --- a/x/logic/keeper/features/asserta_1.feature +++ b/x/logic/predicate/features/asserta_1.feature @@ -27,9 +27,9 @@ Feature: asserta/1 results: - substitutions: - variable: X - expression: "john" - - variable: Y - expression: "pete" + expression: john + - variable: 'Y' + expression: pete """ @great_for_documentation @@ -86,10 +86,10 @@ Feature: asserta/1 results: - substitutions: - variable: X - expression: "john" + expression: john - substitutions: - variable: X - expression: "jane" + expression: jane """ @great_for_documentation diff --git a/x/logic/keeper/features/assertz_1.feature b/x/logic/predicate/features/assertz_1.feature similarity index 96% rename from x/logic/keeper/features/assertz_1.feature rename to x/logic/predicate/features/assertz_1.feature index 201e908d..1ff38047 100644 --- a/x/logic/keeper/features/assertz_1.feature +++ b/x/logic/predicate/features/assertz_1.feature @@ -27,9 +27,9 @@ Feature: assertz/1 results: - substitutions: - variable: X - expression: "john" - - variable: Y - expression: "pete" + expression: john + - variable: 'Y' + expression: pete """ @great_for_documentation @@ -86,10 +86,10 @@ Feature: assertz/1 results: - substitutions: - variable: X - expression: "jane" + expression: jane - substitutions: - variable: X - expression: "john" + expression: john """ @great_for_documentation diff --git a/x/logic/keeper/features/bech32_address_2.feature b/x/logic/predicate/features/bech32_address_2.feature similarity index 100% rename from x/logic/keeper/features/bech32_address_2.feature rename to x/logic/predicate/features/bech32_address_2.feature diff --git a/x/logic/predicate/features/block_header_1.feature b/x/logic/predicate/features/block_header_1.feature new file mode 100644 index 00000000..3aa0d216 --- /dev/null +++ b/x/logic/predicate/features/block_header_1.feature @@ -0,0 +1,136 @@ +Feature: block_header/1 + This feature is to test the block_header/1 predicate. + + @great_for_documentation + Scenario: Retrieve the header of the current block. + This scenario demonstrates how to retrieve the header of the current block and obtain some of its properties. + + The header of a block carries important information about the state of the blockchain, such as basic information (chain id, the height, + time, and height), the information about the last block, hashes, and the consensus info. + + The header is represented as a Prolog Dict, which is a collection of key-value pairs. + + Given a block with the following header: + """ yaml + app_hash: Q0P6b2hoSUbmpCE6o6Dme4H4FBWqdcpqo89DrpBYSHQ= + chain_id: axone-localnet + height: 33 + next_validators_hash: EIQFMnCDepfXD2e3OeL1QoEfmu6BZQbKR500Wkl4gK0= + proposer_address: yz7PSKMWniQlQWMd7LskBABgDKQ= + time: "2024-11-22T21:22:04.676789Z" + """ + + Given the query: + """ prolog + block_header(Header). + """ + When the query is run + Then the answer we get is: + """ yaml + height: 33 + gas_used: 3975 + answer: + has_more: false + variables: ["Header"] + results: + - substitutions: + - variable: Header + expression: >- + header{app_hash:[67,67,250,111,104,104,73,70,230,164,33,58,163,160,230,123,129,248,20,21,170,117,202,106,163,207,67,174,144,88,72,116],chain_id:'axone-localnet',consensus_hash:[],data_hash:[],evidence_hash:[],height:33,last_block_id:block_id{hash:[],part_set_header:part_set_header{hash:[],total:0}},last_commit_hash:[],last_results_hash:[],next_validators_hash:[16,132,5,50,112,131,122,151,215,15,103,183,57,226,245,66,129,31,154,238,129,101,6,202,71,157,52,90,73,120,128,173],proposer_address:[203,62,207,72,163,22,158,36,37,65,99,29,236,187,36,4,0,96,12,164],time:1732310524,validators_hash:[],version:consensus{app:0,block:0}} + """ + + @great_for_documentation + Scenario: Retrieve the block height of the current block. + This scenario demonstrates how to retrieve the block height of the current block. + + Given a block with the following header: + """ yaml + height: 100 + """ + Given the program: + """ prolog + height(Height) :- + block_header(Header), + Height = Header.height. + """ + Given the query: + """ prolog + height(Height). + """ + When the query is run + Then the answer we get is: + """ yaml + height: 100 + gas_used: 3978 + answer: + has_more: false + variables: ["Height"] + results: + - substitutions: + - variable: Height + expression: "100" + """ + + @great_for_documentation + Scenario: Retrieve the block time of the current block. + This scenario demonstrates how to retrieve the block time of the current block. + + Given a block with the following header: + """ yaml + time: 2024-03-04T11:03:36.000Z + """ + Given the program: + """ prolog + time(Time) :- + block_header(Header), + Time = Header.time. + """ + Given the query: + """ prolog + time(Time). + """ + When the query is run + Then the answer we get is: + """ yaml + height: 42 + gas_used: 3978 + answer: + has_more: false + variables: ["Time"] + results: + - substitutions: + - variable: Time + expression: "1709550216" + """ + + @great_for_documentation + Scenario: Evaluate a condition based on block time and height + This scenario demonstrates how to evaluate a condition that depends on both the block time and block height. + Specifically, it checks whether the block time is greater than 1709550216 seconds (Monday 4 March 2024 11:03:36 GMT) + or the block height is greater than 42. + + Given a block with the following header: + """ yaml + time: 2024-03-04T11:03:37.000Z + """ + Given the program: + """ prolog + evaluate :- + block_header(Header), + (Header.time > 1709550216; Header.height > 42), + !. + """ + Given the query: + """ prolog + evaluate. + """ + When the query is run + Then the answer we get is: + """ yaml + height: 42 + gas_used: 3981 + answer: + has_more: false + results: + - substitutions: + """ diff --git a/x/logic/keeper/features/consult_1.feature b/x/logic/predicate/features/consult_1.feature similarity index 100% rename from x/logic/keeper/features/consult_1.feature rename to x/logic/predicate/features/consult_1.feature diff --git a/x/logic/keeper/features/current_output_1.feature b/x/logic/predicate/features/current_output_1.feature similarity index 100% rename from x/logic/keeper/features/current_output_1.feature rename to x/logic/predicate/features/current_output_1.feature diff --git a/x/logic/keeper/features/open_3.feature b/x/logic/predicate/features/open_3.feature similarity index 100% rename from x/logic/keeper/features/open_3.feature rename to x/logic/predicate/features/open_3.feature diff --git a/x/logic/keeper/features/open_4.feature b/x/logic/predicate/features/open_4.feature similarity index 100% rename from x/logic/keeper/features/open_4.feature rename to x/logic/predicate/features/open_4.feature diff --git a/x/logic/keeper/features/retract_1.feature b/x/logic/predicate/features/retract_1.feature similarity index 100% rename from x/logic/keeper/features/retract_1.feature rename to x/logic/predicate/features/retract_1.feature diff --git a/x/logic/keeper/features_test.go b/x/logic/predicate/features_test.go similarity index 89% rename from x/logic/keeper/features_test.go rename to x/logic/predicate/features_test.go index 725779c2..b575f6e7 100644 --- a/x/logic/keeper/features_test.go +++ b/x/logic/predicate/features_test.go @@ -1,4 +1,4 @@ -package keeper_test +package predicate_test import ( "context" @@ -7,7 +7,6 @@ import ( "fmt" "io/fs" "reflect" - "strconv" "strings" "testing" "time" @@ -17,7 +16,7 @@ import ( "github.com/sergi/go-diff/diffmatchpatch" "github.com/smartystreets/goconvey/convey/reporting" "go.uber.org/mock/gomock" - "gopkg.in/yaml.v3" + "sigs.k8s.io/yaml" . "github.com/smartystreets/goconvey/convey" @@ -83,28 +82,15 @@ func testCaseFromContext(ctx context.Context) *testCase { return tc } -func givenABlockWithTheFollowingHeader(ctx context.Context, table *godog.Table) error { +func givenABlockWithTheFollowingHeader(ctx context.Context, headerConfig *godog.DocString) error { tc := testCaseFromContext(ctx) header := tc.ctx.Ctx.BlockHeader() - for _, row := range table.Rows { - switch row.Cells[0].Value { - case "Height": - height, err := atoi64(row.Cells[1].Value) - if err != nil { - return err - } - header.Height = height - case "Time": - sec, err := atoi64(row.Cells[1].Value) - if err != nil { - return err - } - header.Time = time.Unix(sec, 0) - default: - return fmt.Errorf("unknown field: %s", row.Cells[0].Value) - } + + if err := parseDocStringYaml(headerConfig, &header); err != nil { + return err } + tc.ctx.Ctx = tc.ctx.Ctx.WithBlockHeader(header) return nil @@ -135,10 +121,7 @@ func givenTheProgram(ctx context.Context, program *godog.DocString) error { func givenASmartContractWithAddress(ctx context.Context, address string, configuration *godog.DocString) error { smartContractConfiguration := &SmartContractConfiguration{} - if strings.TrimSpace(configuration.MediaType) != "yaml" { - return fmt.Errorf("unsupported media type: %s. Want %s", configuration.MediaType, "yaml") - } - if err := yaml.Unmarshal([]byte(configuration.Content), &smartContractConfiguration); err != nil { + if err := parseDocStringYaml(configuration, smartContractConfiguration); err != nil { return err } @@ -214,7 +197,7 @@ func whenTheQueryIsRunLimitedToNSolutions(ctx context.Context, n int) error { func theAnswerWeGetIs(ctx context.Context, want *godog.DocString) error { got := testCaseFromContext(ctx).got wantAnswer := &types.QueryServiceAskResponse{} - if err := yaml.Unmarshal([]byte(want.Content), &wantAnswer); err != nil { + if err := parseDocStringYaml(want, wantAnswer); err != nil { return err } @@ -321,10 +304,15 @@ func logicKeeperParams() types.Params { return params } -func atoi64(s string) (int64, error) { - i, err := strconv.ParseInt(s, 10, 64) - if err != nil { - return 0, err +func parseDocStringYaml(docString *godog.DocString, v interface{}) error { + const yamlMediaType = "yaml" + if strings.TrimSpace(docString.MediaType) != yamlMediaType { + return fmt.Errorf("unsupported media type: %s. Want %s", docString.MediaType, yamlMediaType) + } + + if err := yaml.UnmarshalStrict([]byte(docString.Content), v); err != nil { + return err } - return i, nil + + return nil }