이 문서는 현재 저장소에서 지원하는 contract query HTTP API 사용법을 정리한다.
POST /contract/{contract}/query
request body는 JSON object이고, 반드시 function 키를 포함해야 한다.
{
"function": "GetConfig"
}현재 query endpoint는 raw HTTP body size limit도 적용한다.
- max query body size:
128 KiB
scalar query arg는 기존처럼 plain string이다.
지원 scalar:
stringboolintint64uint64
예:
{
"function": "GetUser",
"name": "alice"
}decode 후 map[string]string payload에도 size limit이 적용된다.
- max entries:
64 - max key bytes:
128 - max value bytes:
16 KiB - max total key+value bytes:
64 KiB
reserved key인 function 도 일반 entry와 동일하게 계산된다.
_sender 는 더 이상 query execution context sender 로 해석되지 않는다. 요청에 들어와도 일반 unused key처럼 payload limit 계산에 포함될 뿐이며, query contract는 chain.QueryContext에서 sender에 접근할 수 없다.
query contract에서 ctx.GetHeight()는 현재 query가 읽는 state/view height다. snapshot-backed typed Gno contract에서는 snapshot state height를 반환한다.
현재 chain head height가 필요하면 query 함수에서 ctx.GetCurrentHeight()를 사용한다. digest query path는 database의 current last block height를 runtime에 전달하며, 이 값은 state/view height와 다를 수 있다. write/register/call path에서는 current head height ABI가 없으며, write execution/block height는 ctx.GetHeight()로 읽는다. chain.CurrentHeight()는 더 이상 canonical contract surface가 아니다.
write-only ctx.GetBlockTime()은 proposal inclusion timestamp를 위한 API이며 query context에는 제공되지 않는다.
allowlist에 있는 stdlib package는 runtime binary에 embedded 된 vendored Gno stdlib bundle에서 로드된다. query/register/write execution은 실행 머신의 $GOMODCACHE, GNOROOT, 또는 로컬 gnovm/stdlibs checkout에 의존하지 않는다. bundle에는 필요한 internal dependency가 포함될 수 있지만, contract가 직접 import할 수 있는 stdlib root는 Contract-language-support.md의 allowlist로 제한된다.
query execution도 VM resource cap으로 gas meter를 사용한다. 이 gas는 transaction fee/billing 의미가 아니라 read-only query가 CPU/step/native call을 과도하게 쓰지 못하게 막는 실행 제한이다.
- write/register/call gas limit:
5,000,000 - query gas limit:
1,000,000
query limit은 write limit의 1/5이며, host native gas table도 query execution에서 동일하게 적용된다. 예를 들어 BalanceOf, AccountExists, IsContractAccount, SHA3Sum256 호출은 query budget을 소비한다. query gas exhaustion은 generic panic이 아니라 gno query out of gas 계열 failure로 드러난다.
contract query/write 함수는 mitum/chain host native로 현재 balance state를 조회할 수 있다.
amount, ok := chain.BalanceOf(addr, currency)Semantics:
amount는 decimal amount string이다.- account, currency design, balance state가 모두 있으면
ok == true. - account 없음, currency 없음, 해당 currency balance state 없음, malformed address, malformed currency는
("", false)로 반환된다. - zero balance는
"0", true로 반환되어 not found와 구분된다. - state decode/type mismatch는 state corruption 성격의 host native failure이며, raw internal detail은 panic sanitization 정책에 따라 HTTP response에 직접 노출되지 않는다.
contract query/write 함수는 deterministic pure host native로 SHA3-256 digest를 계산할 수 있다.
digest := chain.SHA3Sum256(data)Semantics:
- input은
[]byte(data)raw byte sequence다. - hex decode, numeric parse, UTF-8 text normalization은 하지 않는다.
- output은 lowercase hex digest string이다.
- failure result는 없다.
"ff"는 bytes{0x66, 0x66}로 해시된다.
현재 query result는 다음 형태를 지원한다.
T(T, bool)
여기서 T는 아래 범위까지 지원된다.
- scalar
- named struct
map[string]scalarmap[string]named-struct[]scalar[]named-struct
JSON/HAL 응답에서의 shape:
- scalar -> JSON scalar
- struct -> JSON object
- map -> JSON object
- slice -> JSON array
HTTP 응답에서는 query 함수의 반환값을 항상 _embedded.output 아래에 둔다.
- single-result query:
output.result만 포함 (T, bool)query:output.result와output.ok포함
_embedded.result와 _embedded.ok 형태는 더 이상 제공하지 않는다. 이는 메타데이터와 함수 output을 분리하기 위한 즉시 적용 API cleanup이며 compatibility shim은 없다.
응답은 HAL JSON이다.
예:
{
"_embedded": {
"contract": "mitum....",
"function": "GetConfig",
"engine": "gno-snapshot-v1",
"read_only": true,
"output": {
"result": {
"Owner": "alice"
}
}
},
"_links": {
"self": { "href": "/contract/mitum..../query" },
"design": { "href": "/contract/mitum...." },
"block": { "href": "/block/123" }
}
}예:
{
"_embedded": {
"contract": "mitum....",
"function": "GetValueIfPresent",
"engine": "gno-snapshot-v1",
"read_only": true,
"output": {
"result": "5",
"ok": true
}
}
}output.ok == trueoutput.result는 실제 조회된 값을 담는다.
output.ok == falseoutput.result는 해당 타입의 zero-like JSON shape를 담을 수 있다.- 예:
- struct -> field별 zero value / nil map / nil slice
- scalar -> zero scalar
- nil map -> JSON
null - empty map -> JSON
{}
- nil slice -> JSON
null - empty slice -> JSON
[]
현재 아래는 지원하지 않는다.
- anonymous struct arg / result
- non-string map key
- map elem map
- map elem slice
- slice elem map
- slice elem slice
- recursive / mutually recursive struct
- struct query arg
- map query arg
- slice query arg
대표적인 실패 유형:
- malformed JSON ->
400 Bad Request - oversized raw query body ->
413 Request Entity Too Large - decoded
callDatapayload limit 초과 ->400 Bad Request - missing
function->400 Bad Request
scalar query:
curl -X POST \
-H 'Content-Type: application/json' \
-d '{"function":"GetOwner"}' \
http://localhost:54320/contract/<contract>/queryscalar arg query:
curl -X POST \
-H 'Content-Type: application/json' \
-d '{"function":"GetUser","name":"alice"}' \
http://localhost:54320/contract/<contract>/queryscalar multi-arg query:
curl -X POST \
-H 'Content-Type: application/json' \
-d '{"function":"GetUserTagAt","name":"owner","index":"0"}' \
http://localhost:54320/contract/<contract>/query