Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix scvals to print in json string #305

Merged
merged 14 commits into from
Jan 28, 2025
Merged

Fix scvals to print in json string #305

merged 14 commits into from
Jan 28, 2025

Conversation

chowbao
Copy link
Contributor

@chowbao chowbao commented Jan 23, 2025

PR Checklist

PR Structure

  • This PR has reasonably narrow scope (if not, break it down into smaller PRs).
  • This PR avoids mixing refactoring changes with feature changes (split into two PRs
    otherwise).
  • This PR's title starts with the jira ticket associated with the PR.

Thoroughness

  • This PR adds tests for the most critical parts of the new functionality or fixes.
  • I've updated the README with the added features, breaking changes, new instructions on how to use the repository. I updated the description of the fuction with the changes that were made.

Release planning

  • I've decided if this PR requires a new major/minor/patch version accordingly to
    semver, and I've changed the name of the BRANCH to major/_ , minor/_ or patch/* .

What

github issue

Fix printing of ScVals for contract_data and history_contract_events to print in a JSON parsable format

Why

The ScVal.String() function uses the %v to print out the ScVal struct which causes some oddities in how nested maps, arrays, and contract instances were converted to where they did not conform to a normal map/json structure. By fixing ScVals to print in a JSON parsable format we can more easily dive into decoded keys/vals using parse_json() in BigQuery

Known limitations

Edit:

  • xdr2json was copied over from stellar/stellar-rpc and will be updated when xdr2json is moved to a separate library/repo
  • contract_events and contract data have been updated to use xdr2json for ScVals output
  • Schemas needed to be updated to use a generic interface{} rather than the original map[string]string
  • Updated Dockerfile to include a rust image to build the rust code
  • Removed the stellar/core as it is never used in stellar-etl (deprecated when CDP was integrated)
  • Removed Dockerfile.test and updated integration tests to use the same docker/Dockerfile
  • github workflows updated to include the rust cargo build

@chowbao chowbao requested a review from a team as a code owner January 23, 2025 15:57
Copy link
Contributor

@sydneynotthecity sydneynotthecity left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

First pass looks good, just a couple comments

internal/transform/contract_events_test.go Outdated Show resolved Hide resolved
internal/transform/contract_events.go Outdated Show resolved Hide resolved
@leighmcculloch
Copy link
Member

leighmcculloch commented Jan 23, 2025

print in a JSON parsable format

There is a canonical XDR-JSON format that more tooling is using, the Lab uses it, the CLI uses it, the Soroban Rust SDK uses it, and this could use it too. It's implemented in the Rust XDR lib, and that lib is also published as a Wasm powered NPM package. You could take the Wasm and experiment with powering the JSON generation with it too so that you're using the same JSON format.

If the JSON format is largely internal, then this doesn't matter, but has much more value if users see it.

Rust XDR Lib: https://github.com/stellar/rs-stellar-xdr
Wasm-powdered JS Lib: https://github.com/stellar/js-stellar-xdr-json

If this is of interest we can build a Wasm-powered Go lib that does same.

@chowbao
Copy link
Contributor Author

chowbao commented Jan 23, 2025

print in a JSON parsable format

There is a canonical XDR-JSON format that more tooling is using, the Lab uses it, the CLI uses it, the Soroban Rust SDK uses it, and this could use it too. It's implemented in the Rust XDR lib, and that lib is also published as a Wasm powered NPM package. You could take the Wasm and experiment with powering the JSON generation with it too so that you're using the same JSON format.

If the JSON format is largely internal, then this doesn't matter, but has much more value if users see it.

Rust XDR Lib: https://github.com/stellar/rs-stellar-xdr Wasm-powdered JS Lib: https://github.com/stellar/js-stellar-xdr-json

If this is of interest we can build a Wasm-powered Go lib that does same.

Ooo it would be nice if there was the Go lib equivalent. Not sure how much interest there would be for it though.

As it pertains to this PR and change it is purely for stellar-etl (basically internal). I don't believe it is worth porting (or calling rust or js) for this specific case.

You could take the Wasm and experiment with powering the JSON generation with it too so that you're using the same JSON format.

Is there an existing example of this JSON format? I assume it is largely the same because it is just ScVals but doesn't hurt to check.

@leighmcculloch
Copy link
Member

Is there an existing example of this JSON format? I assume it is largely the same because it is just ScVals but doesn't hurt to check.

Install the stellar-cli (e.g. brew install stellar-cli) and then try some of these commands.

The CLI manual is at: https://developers.stellar.org/docs/tools/developer-tools/cli/stellar-cli#stellar-xdr-decode

The following commands example encodes and decodes, they work in reverse with the encode subcommand accepting JSON and the decode command accepting XDR. There are other types of XDR supported too, such as streams (the format that contract specs and meta are in), or framed streams (the format bucket lists are in).

ScVal u128:

$ echo 'AAAACQAAAAAAAAAAAAAAABfzm7A=' | stellar xdr decode --type ScVal
{"u128":{"hi":0,"lo":401841072}}

ScVal symbol:

$ echo '{"symbol":"Balance"}' | stellar xdr encode --type ScVal
AAAADwAAAAdCYWxhbmNlAA==

ScVal vec:

$ stellar xdr encode --type ScVal << -
{
  "vec": [
    {"symbol":"Balance"},
    {"address":"CCZC4HGM2BW7TIIS4KBDQEZX67DFZLOL6TZXGUGD6SJZS6IJ5JUAEZZR"}
  ]
}
-
AAAAEAAAAAEAAAACAAAADwAAAAdCYWxhbmNlAAAAABIAAAABsi4czNBt+aES4oI4Ezf3xlyty/Tzc1DD9JOZeQnqaAI=

TransactionEnvelope:

$ stellar xdr decode --type TransactionEnvelope << -
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
-
{"tx":{"tx":{"source_account":"GA5Z4AU7AFCLJ7CRTFVYFCOHOHLVHKLQCTTQCJHTHDA6Y6ZPHOFFSATE","fee":1524847,"seq_num":231426354170577845,"cond":"none","memo":"none","operations":[{"source_account":"GA5Z4AU7AFCLJ7CRTFVYFCOHOHLVHKLQCTTQCJHTHDA6Y6ZPHOFFSATE","body":{"invoke_host_function":{"host_function":{"invoke_contract":{"contract_address":"CBQDHNBFBZYE4MKPWBSJOPIYLW4SFSXAXUTSXJN76GNKYVYPCKWC6QUK","function_name":"swap_chained","args":[{"address":"GA5Z4AU7AFCLJ7CRTFVYFCOHOHLVHKLQCTTQCJHTHDA6Y6ZPHOFFSATE"},{"vec":[{"vec":[{"vec":[{"address":"CBH4M45TQBLDPXOK6L7VYKMEJWFITBOL64BN3WDAIIDT4LNUTWTTOCKF"},{"address":"CDYEOOVL6WV4JRY45CXQKOBJFFAPOM5KNQCCDNM333L6RM2L4RO3LKYG"}]},{"bytes":"3dcdca256a50352587bfb2b5ae2a7185d661015ef684e2c40f78aafeedd82680"},{"address":"CBH4M45TQBLDPXOK6L7VYKMEJWFITBOL64BN3WDAIIDT4LNUTWTTOCKF"}]},{"vec":[{"vec":[{"address":"CBH4M45TQBLDPXOK6L7VYKMEJWFITBOL64BN3WDAIIDT4LNUTWTTOCKF"},{"address":"CCW67TSZV3SSS2HXMBQ5JFGCKJNXKZM7UQUWUZPUTHXSTZLEO7SJMI75"}]},{"bytes":"9ac7a9cde23ac2ada11105eeaa42e43c2ea8332ca0aa8f41f58d7160274d718e"},{"address":"CCW67TSZV3SSS2HXMBQ5JFGCKJNXKZM7UQUWUZPUTHXSTZLEO7SJMI75"}]},{"vec":[{"vec":[{"address":"CAS3J7GYLGXMF6TDJBBYYSE3HQ6BBSMLNUQ34T6TZMYMW2EVH34XOWMA"},{"address":"CCW67TSZV3SSS2HXMBQ5JFGCKJNXKZM7UQUWUZPUTHXSTZLEO7SJMI75"}]},{"bytes":"b2e02fcfca6c96f8ad5cbd84e7784a777b36d9c96a2459402c4f458462aab7f0"},{"address":"CAS3J7GYLGXMF6TDJBBYYSE3HQ6BBSMLNUQ34T6TZMYMW2EVH34XOWMA"}]}]},{"address":"CDYEOOVL6WV4JRY45CXQKOBJFFAPOM5KNQCCDNM333L6RM2L4RO3LKYG"},{"u128":{"hi":0,"lo":52424}},{"u128":{"hi":0,"lo":401841072}}]}},"auth":[{"credentials":"source_account","root_invocation":{"function":{"contract_fn":{"contract_address":"CBQDHNBFBZYE4MKPWBSJOPIYLW4SFSXAXUTSXJN76GNKYVYPCKWC6QUK","function_name":"swap_chained","args":[{"address":"GA5Z4AU7AFCLJ7CRTFVYFCOHOHLVHKLQCTTQCJHTHDA6Y6ZPHOFFSATE"},{"vec":[{"vec":[{"vec":[{"address":"CBH4M45TQBLDPXOK6L7VYKMEJWFITBOL64BN3WDAIIDT4LNUTWTTOCKF"},{"address":"CDYEOOVL6WV4JRY45CXQKOBJFFAPOM5KNQCCDNM333L6RM2L4RO3LKYG"}]},{"bytes":"3dcdca256a50352587bfb2b5ae2a7185d661015ef684e2c40f78aafeedd82680"},{"address":"CBH4M45TQBLDPXOK6L7VYKMEJWFITBOL64BN3WDAIIDT4LNUTWTTOCKF"}]},{"vec":[{"vec":[{"address":"CBH4M45TQBLDPXOK6L7VYKMEJWFITBOL64BN3WDAIIDT4LNUTWTTOCKF"},{"address":"CCW67TSZV3SSS2HXMBQ5JFGCKJNXKZM7UQUWUZPUTHXSTZLEO7SJMI75"}]},{"bytes":"9ac7a9cde23ac2ada11105eeaa42e43c2ea8332ca0aa8f41f58d7160274d718e"},{"address":"CCW67TSZV3SSS2HXMBQ5JFGCKJNXKZM7UQUWUZPUTHXSTZLEO7SJMI75"}]},{"vec":[{"vec":[{"address":"CAS3J7GYLGXMF6TDJBBYYSE3HQ6BBSMLNUQ34T6TZMYMW2EVH34XOWMA"},{"address":"CCW67TSZV3SSS2HXMBQ5JFGCKJNXKZM7UQUWUZPUTHXSTZLEO7SJMI75"}]},{"bytes":"b2e02fcfca6c96f8ad5cbd84e7784a777b36d9c96a2459402c4f458462aab7f0"},{"address":"CAS3J7GYLGXMF6TDJBBYYSE3HQ6BBSMLNUQ34T6TZMYMW2EVH34XOWMA"}]}]},{"address":"CDYEOOVL6WV4JRY45CXQKOBJFFAPOM5KNQCCDNM333L6RM2L4RO3LKYG"},{"u128":{"hi":0,"lo":52424}},{"u128":{"hi":0,"lo":401841072}}]}},"sub_invocations":[{"function":{"contract_fn":{"contract_address":"CDYEOOVL6WV4JRY45CXQKOBJFFAPOM5KNQCCDNM333L6RM2L4RO3LKYG","function_name":"transfer","args":[{"address":"GA5Z4AU7AFCLJ7CRTFVYFCOHOHLVHKLQCTTQCJHTHDA6Y6ZPHOFFSATE"},{"address":"CBQDHNBFBZYE4MKPWBSJOPIYLW4SFSXAXUTSXJN76GNKYVYPCKWC6QUK"},{"i128":{"hi":0,"lo":52424}}]}},"sub_invocations":[]}]}}]}}}],"ext":{"v1":{"ext":"v0","resources":{"footprint":{"read_only":[{"contract_data":{"contract":"CAS3J7GYLGXMF6TDJBBYYSE3HQ6BBSMLNUQ34T6TZMYMW2EVH34XOWMA","key":"ledger_key_contract_instance","durability":"persistent"}},{"contract_data":{"contract":"CBH4M45TQBLDPXOK6L7VYKMEJWFITBOL64BN3WDAIIDT4LNUTWTTOCKF","key":"ledger_key_contract_instance","durability":"persistent"}},{"contract_data":{"contract":"CBQDHNBFBZYE4MKPWBSJOPIYLW4SFSXAXUTSXJN76GNKYVYPCKWC6QUK","key":{"vec":[{"symbol":"TokensSetPools"},{"bytes":"639930137be0fc432e5e72215c24a2aff2749a8ec90bc9a08acd9d8fb140926c"}]},"durability":"persistent"}},{"contract_data":{"contract":"CBQDHNBFBZYE4MKPWBSJOPIYLW4SFSXAXUTSXJN76GNKYVYPCKWC6QUK","key":{"vec":[{"symbol":"TokensSetPools"},{"bytes":"63ad1a844f8d16541d28d17361c577fe7de188171267ae6dfc990a444ea7309f"}]},"durability":"persistent"}},{"contract_data":{"contract":"CBQDHNBFBZYE4MKPWBSJOPIYLW4SFSXAXUTSXJN76GNKYVYPCKWC6QUK","key":{"vec":[{"symbol":"TokensSetPools"},{"bytes":"fad480d6ebd73d0918b21454fad3a1eb8f80c52ee95e3572320fcee448eb7608"}]},"durability":"persistent"}},{"contract_data":{"contract":"CBQDHNBFBZYE4MKPWBSJOPIYLW4SFSXAXUTSXJN76GNKYVYPCKWC6QUK","key":"ledger_key_contract_instance","durability":"persistent"}},{"contract_data":{"contract":"CCABO2IQYDWRGGQ4DYQ73CV3ZFDBRZTEQNDDJMFT7JZO54CLS4RYJROY","key":"ledger_key_contract_instance","durability":"persistent"}},{"contract_data":{"contract":"CCW67TSZV3SSS2HXMBQ5JFGCKJNXKZM7UQUWUZPUTHXSTZLEO7SJMI75","key":"ledger_key_contract_instance","durability":"persistent"}},{"contract_data":{"contract":"CDYEOOVL6WV4JRY45CXQKOBJFFAPOM5KNQCCDNM333L6RM2L4RO3LKYG","key":"ledger_key_contract_instance","durability":"persistent"}},{"contract_code":{"hash":"26c495019afb7448f690a82d6e66d8fab1ad3fd3e7b4aec7d554209966c9d19d"}},{"contract_code":{"hash":"2d770946d5429b0988fd33904cf19b5498823f668cb69a0a5028e988023d2040"}},{"contract_code":{"hash":"55827b34ba16ff3054796645e0bd31a50e87194cc123dcdd8e0f22e7a2cc9d98"}},{"contract_code":{"hash":"64ef0bc6962f06546c0e00a11877c869d78c08043f79d50ee2c09cb1b837c477"}}],"read_write":[{"account":{"account_id":"GA5Z4AU7AFCLJ7CRTFVYFCOHOHLVHKLQCTTQCJHTHDA6Y6ZPHOFFSATE"}},{"trustline":{"account_id":"GA5Z4AU7AFCLJ7CRTFVYFCOHOHLVHKLQCTTQCJHTHDA6Y6ZPHOFFSATE","asset":{"credit_alphanum4":{"asset_code":"yETH","issuer":"GDYQNEF2UWTK4L6HITMT53MZ6F5QWO3Q4UVE6SCGC4OMEQIZQQDERQFD"}}}},{"contract_data":{"contract":"CAS3J7GYLGXMF6TDJBBYYSE3HQ6BBSMLNUQ34T6TZMYMW2EVH34XOWMA","key":{"vec":[{"symbol":"Balance"},{"address":"CA6PUJLBYKZKUEKLZJMKBZLEKP2OTHANDEOWSFF44FTSYLKQPIICCJBE"}]},"durability":"persistent"}},{"contract_data":{"contract":"CAS3J7GYLGXMF6TDJBBYYSE3HQ6BBSMLNUQ34T6TZMYMW2EVH34XOWMA","key":{"vec":[{"symbol":"Balance"},{"address":"CBQDHNBFBZYE4MKPWBSJOPIYLW4SFSXAXUTSXJN76GNKYVYPCKWC6QUK"}]},"durability":"persistent"}},{"contract_data":{"contract":"CA6PUJLBYKZKUEKLZJMKBZLEKP2OTHANDEOWSFF44FTSYLKQPIICCJBE","key":"ledger_key_contract_instance","durability":"persistent"}},{"contract_data":{"contract":"CBH4M45TQBLDPXOK6L7VYKMEJWFITBOL64BN3WDAIIDT4LNUTWTTOCKF","key":{"vec":[{"symbol":"Balance"},{"address":"CBQDHNBFBZYE4MKPWBSJOPIYLW4SFSXAXUTSXJN76GNKYVYPCKWC6QUK"}]},"durability":"persistent"}},{"contract_data":{"contract":"CBH4M45TQBLDPXOK6L7VYKMEJWFITBOL64BN3WDAIIDT4LNUTWTTOCKF","key":{"vec":[{"symbol":"Balance"},{"address":"CCOZA42SRNHEMT7SBPAX5BG7BJXTTCHJ56FYCQRYB35CP5WUVEXM7B3F"}]},"durability":"persistent"}},{"contract_data":{"contract":"CBH4M45TQBLDPXOK6L7VYKMEJWFITBOL64BN3WDAIIDT4LNUTWTTOCKF","key":{"vec":[{"symbol":"Balance"},{"address":"CCZC4HGM2BW7TIIS4KBDQEZX67DFZLOL6TZXGUGD6SJZS6IJ5JUAEZZR"}]},"durability":"persistent"}},{"contract_data":{"contract":"CCABO2IQYDWRGGQ4DYQ73CV3ZFDBRZTEQNDDJMFT7JZO54CLS4RYJROY","key":{"vec":[{"symbol":"PoolData"},{"address":"CA6PUJLBYKZKUEKLZJMKBZLEKP2OTHANDEOWSFF44FTSYLKQPIICCJBE"}]},"durability":"persistent"}},{"contract_data":{"contract":"CCABO2IQYDWRGGQ4DYQ73CV3ZFDBRZTEQNDDJMFT7JZO54CLS4RYJROY","key":{"vec":[{"symbol":"PoolData"},{"address":"CCOZA42SRNHEMT7SBPAX5BG7BJXTTCHJ56FYCQRYB35CP5WUVEXM7B3F"}]},"durability":"persistent"}},{"contract_data":{"contract":"CCABO2IQYDWRGGQ4DYQ73CV3ZFDBRZTEQNDDJMFT7JZO54CLS4RYJROY","key":{"vec":[{"symbol":"PoolData"},{"address":"CCZC4HGM2BW7TIIS4KBDQEZX67DFZLOL6TZXGUGD6SJZS6IJ5JUAEZZR"}]},"durability":"persistent"}},{"contract_data":{"contract":"CCOZA42SRNHEMT7SBPAX5BG7BJXTTCHJ56FYCQRYB35CP5WUVEXM7B3F","key":"ledger_key_contract_instance","durability":"persistent"}},{"contract_data":{"contract":"CCW67TSZV3SSS2HXMBQ5JFGCKJNXKZM7UQUWUZPUTHXSTZLEO7SJMI75","key":{"vec":[{"symbol":"Balance"},{"address":"CA6PUJLBYKZKUEKLZJMKBZLEKP2OTHANDEOWSFF44FTSYLKQPIICCJBE"}]},"durability":"persistent"}},{"contract_data":{"contract":"CCW67TSZV3SSS2HXMBQ5JFGCKJNXKZM7UQUWUZPUTHXSTZLEO7SJMI75","key":{"vec":[{"symbol":"Balance"},{"address":"CBQDHNBFBZYE4MKPWBSJOPIYLW4SFSXAXUTSXJN76GNKYVYPCKWC6QUK"}]},"durability":"persistent"}},{"contract_data":{"contract":"CCW67TSZV3SSS2HXMBQ5JFGCKJNXKZM7UQUWUZPUTHXSTZLEO7SJMI75","key":{"vec":[{"symbol":"Balance"},{"address":"CCZC4HGM2BW7TIIS4KBDQEZX67DFZLOL6TZXGUGD6SJZS6IJ5JUAEZZR"}]},"durability":"persistent"}},{"contract_data":{"contract":"CCZC4HGM2BW7TIIS4KBDQEZX67DFZLOL6TZXGUGD6SJZS6IJ5JUAEZZR","key":"ledger_key_contract_instance","durability":"persistent"}},{"contract_data":{"contract":"CDYEOOVL6WV4JRY45CXQKOBJFFAPOM5KNQCCDNM333L6RM2L4RO3LKYG","key":{"vec":[{"symbol":"Balance"},{"address":"CBQDHNBFBZYE4MKPWBSJOPIYLW4SFSXAXUTSXJN76GNKYVYPCKWC6QUK"}]},"durability":"persistent"}},{"contract_data":{"contract":"CDYEOOVL6WV4JRY45CXQKOBJFFAPOM5KNQCCDNM333L6RM2L4RO3LKYG","key":{"vec":[{"symbol":"Balance"},{"address":"CCOZA42SRNHEMT7SBPAX5BG7BJXTTCHJ56FYCQRYB35CP5WUVEXM7B3F"}]},"durability":"persistent"}}]},"instructions":34423197,"read_bytes":149396,"write_bytes":8864},"resource_fee":1424847}}},"signatures":[{"hint":"2f3b8a59","signature":"f679d8e22aeed41ead916c3e71de6339c1975b7f49778b53d0e445fb771c4ed6de6957200b02bb08fd59a804a1dbe488160e4490bfbbc292275986ef9ad3140c"}]}}

If you're not sure what a type is, use echo 'AAAz...' | stellar xdr guess.

If there are any ideas for improvement to the stellar xdr command, please open them on https://github.com/stellar/rs-stellar-xdr. ❤️

Some things worth calling out:

The JSON output will include 64-bit integers, so you need to use a custom JSON parser, which is easy, in JavaScript runtimes which only support integers up to 53-bits. This won't impact Go usage, or most non-JS runtimes, that supports 64-bit integers in JSON.

Strings are escaped ascii UTF-8 encoded, not simply UTF-8 encoded.

These two attributes aren't well documented in the dev docs, but added them now:

@leighmcculloch
Copy link
Member

The JSON can also be explored at:

Comment on lines 149 to 154
jsonMessage, err = xdr2json.ConvertBytes(xdr.ScVal{}, raw)
if err != nil {
return nil, nil, err
}

serializedDataDecoded["value"] = string(jsonMessage)
Copy link
Contributor Author

@chowbao chowbao Jan 24, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is the xdr2json. It works pretty well and will now output like

{
  "type": "Instance",
  "value": "{\"contract_instance\":{\"executable\":\"stellar_asset\",\"storage\":[{\"key\":{\"symbol\":\"METADATA\"},\"val\":{\"map\":[{\"key\":{\"symbol\":\"decimal\"},\"val\":{\"u32\":7}},{\"key\":{\"symbol\":\"name\"},\"val\":{\"string\":\"EURMTL:GACKTN5DAZGWXRWB2WLM6OPBDHAMT6SJNGLJZPQMEZBUR4JUGBX2UK7V\"}},{\"key\":{\"symbol\":\"symbol\"},\"val\":{\"string\":\"EURMTL\"}}]}},{\"key\":{\"vec\":[{\"symbol\":\"Admin\"}]},\"val\":{\"address\":\"GACKTN5DAZGWXRWB2WLM6OPBDHAMT6SJNGLJZPQMEZBUR4JUGBX2UK7V\"}},{\"key\":{\"vec\":[{\"symbol\":\"AssetInfo\"}]},\"val\":{\"vec\":[{\"symbol\":\"AlphaNum12\"},{\"map\":[{\"key\":{\"symbol\":\"asset_code\"},\"val\":{\"string\":\"EURMTL\\\\0\\\\0\\\\0\\\\0\\\\0\\\\0\"}},{\"key\":{\"symbol\":\"issuer\"},\"val\":{\"bytes\":\"04a9b7a3064d6bc6c1d596cf39e119c0c9fa4969969cbe0c264348f134306faa\"}}]}]}}]}}"
}

How does this look now @sydneynotthecity @leighmcculloch

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yeah i like this better than cli. i don't like that we've copied over xdr2json and think that that should be published as its own package but that's outside the scope of this work.

do you think there is merit in us using xdr2json to parse operation details in the future? this looks much simpler to parse vs what we have to do today

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it depends. For the nested params (also ScVals) for invoke host function yes this makes sense. For some of the other operations where we do some mafhs or add extra non-xdr labels maybe 🤷‍♀️
I think we could technically redesign the operations.Details field as a whole too.

Definitely worth a spike though

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why does the value have two layers of JSON? The outer layer doesn't look like the canonical xdr-json format.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The outer layer is not. There's a few things that need to be reworked (mentioned it should be put back in draft).

I think it's debatable whether or not to remove that outer layer or not.

Pros with the extra Type/Value outer layer

  • Gives a fast/easy way for big query to filter by Type (e.g., I'm only looking for ScMaps)
  • The value in the outer layer Type is equivalent to ArmForSwitch(ScVal.Type) strings rather than the string names from xdr2json (e.g., Instance vs contract_instance). I don't know if there is an existing list of the type names like in the xdr const or ArmForSwitch()
  • iirc the JSON type in BQ is weird and can't pass the xdr2json json directly to the JSON type column in BQ. This is why we have like a BQ column named topics_decoded but the JSON inside also starts with topics_decoded meaning to access it you have to select topics_decoded.topics_decoded.<the json field you want>

Cons

  • Technically the JSON by itself will probably be good enough for anything the data team or anyone else wants to do.
  • 1 less column means storage/cost savings in BQ

One thing I should do is I think we can save it as a JSON instead of string(json). This will depend on how many schema changes and if it's okay to change to a generic interface{}.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

FYI the json isn't stable between protocol versions. I mean it won't change unnecessarily, but xdr structure can change in ways that is binary backwards compatible but not structurally backwards compatible.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can't pass the xdr2json json directly to the JSON type column in BQ

Would be helpful to get some feedback about the structure of the json and what you'd change if anything.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

FYI the json isn't stable between protocol versions. I mean it won't change unnecessarily, but xdr structure can change in ways that is binary backwards compatible but not structurally backwards compatible.

That's unfortunate but makes sense (aka unified event changes)

Yup I'll revise and update with the proposed structure on Monday for y'all's review. I'll add some examples SQL queries to show what it'll look like in BQ as well

Copy link
Contributor Author

@chowbao chowbao Jan 27, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thinking and playing with the ScVal column in BQ I think it makes sense to just make everything a generic interface (use whatever xdr2json spits out). The main reason I liked the outer layer was for easier filtering BUT I think that filtering ScVal types will be rare but still possible in BQ. And if it is a pain this change could be added downstream (dbt model for enriched contract events) keeping the history_contract_events table at its rawest form.

Another benefit is the human names for the ScVal types from xdr2json are nicer than the ArmForSwitch. Not sure why they diverged but I would say it'd be easy enough to make a new map/const/enum for the xdr2json names if needed (or I wonder if we can update ArmForSwitch).

Example traversing column in BQ is still the same except with the xdr2json names

select
  val_decoded.contract_instance.storage[0].val.map.symbol
from history_contract_events

Example filtering in BQ

select
  val_decoded
from history_contract_events
where true
  -- filter for only contract_instance isn't that difficult but less straightforward
  and json_extract(val_decoded, '$.contract_instance') is not null

Original filtering in BQ

select
  val_decoded
where true
  -- ArmForSwitch name for Type
  and val_decoded.Type in ("Instance")

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not sure why they diverged

There's a few things that the Rust xdr lib does that we didn't implement in other xdr libs:

  • Arm names are reduced to their unique text, so if they have a long prefix shared among them, that prefix disappears. Unfortunately this doesn't work for single value enums 😅
  • Anything representable by a strkey is rendered as the strkey instead of the structure it contains.
  • Asset codes are rendered as escaped ascii instead of hex, base64, or hope-for-the-best utf8.

Copy link

socket-security bot commented Jan 24, 2025

Updated dependencies detected. Learn more about Socket for GitHub ↗︎

Package New capabilities Transitives Size Publisher
golang/github.com/stellar/[email protected] 🔁 golang/github.com/stellar/[email protected] eval 0 14.3 MB

View full report↗︎

Makefile Show resolved Hide resolved
@chowbao
Copy link
Contributor Author

chowbao commented Jan 28, 2025

Ready for review again

tl;dr

  • xdr2json was copied over from stellar/stellar-rpc and will be updated when xdr2json is moved to a separate library/repo
  • contract_events and contract data have been updated to use xdr2json for ScVals output
  • Schemas needed to be updated to use a generic interface{} rather than the original map[string]string
  • Updated Dockerfile to include a rust image to build the rust code
  • Removed the stellar/core as it is never used in stellar-etl (deprecated when CDP was integrated)
  • Removed Dockerfile.test and updated integration tests to use the same docker/Dockerfile
  • github workflows updated to include the rust cargo build

@sydneynotthecity
Copy link
Contributor

Schemas needed to be updated to use a generic interface{} rather than the original map[string]string

Does this mean there will need to be a schema change or data type change in BigQuery as well? If there are downstream implications we'll need to coordinate with dependent partners so that we don't break them.

@chowbao
Copy link
Contributor Author

chowbao commented Jan 28, 2025

Schemas needed to be updated to use a generic interface{} rather than the original map[string]string

Does this mean there will need to be a schema change or data type change in BigQuery as well? If there are downstream implications we'll need to coordinate with dependent partners so that we don't break them.

There won't be any downstream data type changes. It is still JSON BQ data type.

There will be implications if anything is built on top of the contents of these ScVals which seems unlikely because they were barely parseable before

Copy link
Contributor

@sydneynotthecity sydneynotthecity left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM, i didn't review the xdr2json lib itself and assume that it matches the original

docker/Dockerfile Show resolved Hide resolved
@chowbao chowbao merged commit ecfd133 into master Jan 28, 2025
8 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants