v1.2 instruction and account decoding backports (#10939)
* Revert "Rpc: add filter to getProgramAccounts (#10888) (#10932)" This reverts commit9311a6e356
. * Add jsonParsed option for EncodedTransactions; add memo parser (#10711) * Add jsonParsed option for EncodedTransactions; add memo parser * Use kebab case for program names * Add account-key parsing * Add parse test * Update transaction encoding docs (#10833) * Add account-decoder utilities (#10846) * Fix comment and make less pub * Add account-decoder crate and use to decode vote and system (nonce) accounts * Update docs * Rename RpcAccount struct * s/Rpc/Display * Call it jsonParsed and update docs * Revert "s/Rpc/Display" This reverts commit6e7149f503
. * s/Rpc/Ui * Add tests * Ui more things * Comments * Update struct prefixes to Ui (#10874) * Update comments * Use Ui prefix * Rpc: add filter to getProgramAccounts (#10888) * Add RpcFilterType, and implement CompareBytes for getProgramAccounts * Accept bytes in bs58 * Rename to memcmp * Add Memcmp optional encoding field * Add dataSize filter * Update docs * Clippy * Simplify tests that don't need to test account contents; add multiple-filter tests
This commit is contained in:
169
Cargo.lock
generated
169
Cargo.lock
generated
@ -3691,6 +3691,23 @@ dependencies = [
|
|||||||
"winapi 0.3.8",
|
"winapi 0.3.8",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "solana-account-decoder"
|
||||||
|
version = "1.2.9"
|
||||||
|
dependencies = [
|
||||||
|
"Inflector",
|
||||||
|
"bincode",
|
||||||
|
"bs58 0.3.1",
|
||||||
|
"lazy_static",
|
||||||
|
"serde",
|
||||||
|
"serde_derive",
|
||||||
|
"serde_json",
|
||||||
|
"solana-sdk 1.2.9",
|
||||||
|
"solana-vote-program",
|
||||||
|
"spl-memo",
|
||||||
|
"thiserror",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "solana-accounts-bench"
|
name = "solana-accounts-bench"
|
||||||
version = "1.2.9"
|
version = "1.2.9"
|
||||||
@ -3703,7 +3720,7 @@ dependencies = [
|
|||||||
"solana-logger",
|
"solana-logger",
|
||||||
"solana-measure",
|
"solana-measure",
|
||||||
"solana-runtime",
|
"solana-runtime",
|
||||||
"solana-sdk",
|
"solana-sdk 1.2.9",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@ -3722,7 +3739,7 @@ dependencies = [
|
|||||||
"solana-measure",
|
"solana-measure",
|
||||||
"solana-perf",
|
"solana-perf",
|
||||||
"solana-runtime",
|
"solana-runtime",
|
||||||
"solana-sdk",
|
"solana-sdk 1.2.9",
|
||||||
"solana-streamer",
|
"solana-streamer",
|
||||||
"solana-version",
|
"solana-version",
|
||||||
]
|
]
|
||||||
@ -3751,7 +3768,7 @@ dependencies = [
|
|||||||
"solana-metrics",
|
"solana-metrics",
|
||||||
"solana-net-utils",
|
"solana-net-utils",
|
||||||
"solana-runtime",
|
"solana-runtime",
|
||||||
"solana-sdk",
|
"solana-sdk 1.2.9",
|
||||||
"solana-version",
|
"solana-version",
|
||||||
]
|
]
|
||||||
|
|
||||||
@ -3792,7 +3809,7 @@ dependencies = [
|
|||||||
"solana-move-loader-program",
|
"solana-move-loader-program",
|
||||||
"solana-net-utils",
|
"solana-net-utils",
|
||||||
"solana-runtime",
|
"solana-runtime",
|
||||||
"solana-sdk",
|
"solana-sdk 1.2.9",
|
||||||
"solana-version",
|
"solana-version",
|
||||||
]
|
]
|
||||||
|
|
||||||
@ -3809,7 +3826,7 @@ dependencies = [
|
|||||||
"rand 0.7.3",
|
"rand 0.7.3",
|
||||||
"solana-logger",
|
"solana-logger",
|
||||||
"solana-runtime",
|
"solana-runtime",
|
||||||
"solana-sdk",
|
"solana-sdk 1.2.9",
|
||||||
"solana_rbpf",
|
"solana_rbpf",
|
||||||
"thiserror",
|
"thiserror",
|
||||||
]
|
]
|
||||||
@ -3825,7 +3842,7 @@ dependencies = [
|
|||||||
"num-traits",
|
"num-traits",
|
||||||
"serde",
|
"serde",
|
||||||
"serde_derive",
|
"serde_derive",
|
||||||
"solana-sdk",
|
"solana-sdk 1.2.9",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@ -3840,7 +3857,7 @@ dependencies = [
|
|||||||
"serde",
|
"serde",
|
||||||
"serde_derive",
|
"serde_derive",
|
||||||
"solana-runtime",
|
"solana-runtime",
|
||||||
"solana-sdk",
|
"solana-sdk 1.2.9",
|
||||||
"thiserror",
|
"thiserror",
|
||||||
]
|
]
|
||||||
|
|
||||||
@ -3852,7 +3869,7 @@ dependencies = [
|
|||||||
"clap",
|
"clap",
|
||||||
"rpassword",
|
"rpassword",
|
||||||
"solana-remote-wallet",
|
"solana-remote-wallet",
|
||||||
"solana-sdk",
|
"solana-sdk 1.2.9",
|
||||||
"thiserror",
|
"thiserror",
|
||||||
"tiny-bip39",
|
"tiny-bip39",
|
||||||
"url 2.1.1",
|
"url 2.1.1",
|
||||||
@ -3880,6 +3897,7 @@ dependencies = [
|
|||||||
"serde",
|
"serde",
|
||||||
"serde_derive",
|
"serde_derive",
|
||||||
"serde_json",
|
"serde_json",
|
||||||
|
"solana-account-decoder",
|
||||||
"solana-budget-program",
|
"solana-budget-program",
|
||||||
"solana-clap-utils",
|
"solana-clap-utils",
|
||||||
"solana-cli-config",
|
"solana-cli-config",
|
||||||
@ -3891,7 +3909,7 @@ dependencies = [
|
|||||||
"solana-net-utils",
|
"solana-net-utils",
|
||||||
"solana-remote-wallet",
|
"solana-remote-wallet",
|
||||||
"solana-runtime",
|
"solana-runtime",
|
||||||
"solana-sdk",
|
"solana-sdk 1.2.9",
|
||||||
"solana-stake-program",
|
"solana-stake-program",
|
||||||
"solana-transaction-status",
|
"solana-transaction-status",
|
||||||
"solana-version",
|
"solana-version",
|
||||||
@ -3930,9 +3948,10 @@ dependencies = [
|
|||||||
"serde",
|
"serde",
|
||||||
"serde_derive",
|
"serde_derive",
|
||||||
"serde_json",
|
"serde_json",
|
||||||
|
"solana-account-decoder",
|
||||||
"solana-logger",
|
"solana-logger",
|
||||||
"solana-net-utils",
|
"solana-net-utils",
|
||||||
"solana-sdk",
|
"solana-sdk 1.2.9",
|
||||||
"solana-transaction-status",
|
"solana-transaction-status",
|
||||||
"solana-vote-program",
|
"solana-vote-program",
|
||||||
"thiserror",
|
"thiserror",
|
||||||
@ -3950,7 +3969,7 @@ dependencies = [
|
|||||||
"serde",
|
"serde",
|
||||||
"serde_derive",
|
"serde_derive",
|
||||||
"solana-logger",
|
"solana-logger",
|
||||||
"solana-sdk",
|
"solana-sdk 1.2.9",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@ -3989,6 +4008,7 @@ dependencies = [
|
|||||||
"serde_json",
|
"serde_json",
|
||||||
"serial_test",
|
"serial_test",
|
||||||
"serial_test_derive",
|
"serial_test_derive",
|
||||||
|
"solana-account-decoder",
|
||||||
"solana-bpf-loader-program",
|
"solana-bpf-loader-program",
|
||||||
"solana-budget-program",
|
"solana-budget-program",
|
||||||
"solana-clap-utils",
|
"solana-clap-utils",
|
||||||
@ -4004,7 +4024,7 @@ dependencies = [
|
|||||||
"solana-perf",
|
"solana-perf",
|
||||||
"solana-rayon-threadlimit",
|
"solana-rayon-threadlimit",
|
||||||
"solana-runtime",
|
"solana-runtime",
|
||||||
"solana-sdk",
|
"solana-sdk 1.2.9",
|
||||||
"solana-stake-program",
|
"solana-stake-program",
|
||||||
"solana-streamer",
|
"solana-streamer",
|
||||||
"solana-sys-tuner",
|
"solana-sys-tuner",
|
||||||
@ -4060,7 +4080,7 @@ dependencies = [
|
|||||||
"solana-logger",
|
"solana-logger",
|
||||||
"solana-net-utils",
|
"solana-net-utils",
|
||||||
"solana-runtime",
|
"solana-runtime",
|
||||||
"solana-sdk",
|
"solana-sdk 1.2.9",
|
||||||
"solana-version",
|
"solana-version",
|
||||||
]
|
]
|
||||||
|
|
||||||
@ -4074,7 +4094,7 @@ dependencies = [
|
|||||||
"log 0.4.8",
|
"log 0.4.8",
|
||||||
"reqwest",
|
"reqwest",
|
||||||
"solana-ledger",
|
"solana-ledger",
|
||||||
"solana-sdk",
|
"solana-sdk 1.2.9",
|
||||||
"tar",
|
"tar",
|
||||||
]
|
]
|
||||||
|
|
||||||
@ -4091,7 +4111,7 @@ dependencies = [
|
|||||||
"solana-logger",
|
"solana-logger",
|
||||||
"solana-metrics",
|
"solana-metrics",
|
||||||
"solana-runtime",
|
"solana-runtime",
|
||||||
"solana-sdk",
|
"solana-sdk 1.2.9",
|
||||||
"thiserror",
|
"thiserror",
|
||||||
]
|
]
|
||||||
|
|
||||||
@ -4100,7 +4120,7 @@ name = "solana-failure-program"
|
|||||||
version = "1.2.9"
|
version = "1.2.9"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"solana-runtime",
|
"solana-runtime",
|
||||||
"solana-sdk",
|
"solana-sdk 1.2.9",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@ -4117,7 +4137,7 @@ dependencies = [
|
|||||||
"solana-clap-utils",
|
"solana-clap-utils",
|
||||||
"solana-logger",
|
"solana-logger",
|
||||||
"solana-metrics",
|
"solana-metrics",
|
||||||
"solana-sdk",
|
"solana-sdk 1.2.9",
|
||||||
"solana-version",
|
"solana-version",
|
||||||
"tokio 0.1.22",
|
"tokio 0.1.22",
|
||||||
"tokio-codec",
|
"tokio-codec",
|
||||||
@ -4137,7 +4157,7 @@ dependencies = [
|
|||||||
"solana-genesis-programs",
|
"solana-genesis-programs",
|
||||||
"solana-ledger",
|
"solana-ledger",
|
||||||
"solana-logger",
|
"solana-logger",
|
||||||
"solana-sdk",
|
"solana-sdk 1.2.9",
|
||||||
"solana-stake-program",
|
"solana-stake-program",
|
||||||
"solana-version",
|
"solana-version",
|
||||||
"solana-vote-program",
|
"solana-vote-program",
|
||||||
@ -4153,7 +4173,7 @@ dependencies = [
|
|||||||
"solana-budget-program",
|
"solana-budget-program",
|
||||||
"solana-exchange-program",
|
"solana-exchange-program",
|
||||||
"solana-runtime",
|
"solana-runtime",
|
||||||
"solana-sdk",
|
"solana-sdk 1.2.9",
|
||||||
"solana-vest-program",
|
"solana-vest-program",
|
||||||
]
|
]
|
||||||
|
|
||||||
@ -4167,7 +4187,7 @@ dependencies = [
|
|||||||
"solana-core",
|
"solana-core",
|
||||||
"solana-logger",
|
"solana-logger",
|
||||||
"solana-net-utils",
|
"solana-net-utils",
|
||||||
"solana-sdk",
|
"solana-sdk 1.2.9",
|
||||||
"solana-version",
|
"solana-version",
|
||||||
]
|
]
|
||||||
|
|
||||||
@ -4195,7 +4215,7 @@ dependencies = [
|
|||||||
"solana-client",
|
"solana-client",
|
||||||
"solana-config-program",
|
"solana-config-program",
|
||||||
"solana-logger",
|
"solana-logger",
|
||||||
"solana-sdk",
|
"solana-sdk 1.2.9",
|
||||||
"solana-version",
|
"solana-version",
|
||||||
"tar",
|
"tar",
|
||||||
"tempdir",
|
"tempdir",
|
||||||
@ -4215,7 +4235,7 @@ dependencies = [
|
|||||||
"solana-clap-utils",
|
"solana-clap-utils",
|
||||||
"solana-cli-config",
|
"solana-cli-config",
|
||||||
"solana-remote-wallet",
|
"solana-remote-wallet",
|
||||||
"solana-sdk",
|
"solana-sdk 1.2.9",
|
||||||
"solana-version",
|
"solana-version",
|
||||||
"tiny-bip39",
|
"tiny-bip39",
|
||||||
]
|
]
|
||||||
@ -4260,7 +4280,7 @@ dependencies = [
|
|||||||
"solana-perf",
|
"solana-perf",
|
||||||
"solana-rayon-threadlimit",
|
"solana-rayon-threadlimit",
|
||||||
"solana-runtime",
|
"solana-runtime",
|
||||||
"solana-sdk",
|
"solana-sdk 1.2.9",
|
||||||
"solana-stake-program",
|
"solana-stake-program",
|
||||||
"solana-transaction-status",
|
"solana-transaction-status",
|
||||||
"solana-vote-program",
|
"solana-vote-program",
|
||||||
@ -4291,7 +4311,7 @@ dependencies = [
|
|||||||
"solana-ledger",
|
"solana-ledger",
|
||||||
"solana-logger",
|
"solana-logger",
|
||||||
"solana-runtime",
|
"solana-runtime",
|
||||||
"solana-sdk",
|
"solana-sdk 1.2.9",
|
||||||
"solana-stake-program",
|
"solana-stake-program",
|
||||||
"solana-transaction-status",
|
"solana-transaction-status",
|
||||||
"solana-version",
|
"solana-version",
|
||||||
@ -4308,7 +4328,7 @@ dependencies = [
|
|||||||
"solana-logger",
|
"solana-logger",
|
||||||
"solana-move-loader-program",
|
"solana-move-loader-program",
|
||||||
"solana-runtime",
|
"solana-runtime",
|
||||||
"solana-sdk",
|
"solana-sdk 1.2.9",
|
||||||
"solana_libra_types",
|
"solana_libra_types",
|
||||||
]
|
]
|
||||||
|
|
||||||
@ -4333,7 +4353,7 @@ dependencies = [
|
|||||||
"solana-logger",
|
"solana-logger",
|
||||||
"solana-rayon-threadlimit",
|
"solana-rayon-threadlimit",
|
||||||
"solana-runtime",
|
"solana-runtime",
|
||||||
"solana-sdk",
|
"solana-sdk 1.2.9",
|
||||||
"solana-stake-program",
|
"solana-stake-program",
|
||||||
"solana-vest-program",
|
"solana-vest-program",
|
||||||
"solana-vote-program",
|
"solana-vote-program",
|
||||||
@ -4370,7 +4390,7 @@ dependencies = [
|
|||||||
"jemallocator",
|
"jemallocator",
|
||||||
"log 0.4.8",
|
"log 0.4.8",
|
||||||
"solana-metrics",
|
"solana-metrics",
|
||||||
"solana-sdk",
|
"solana-sdk 1.2.9",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@ -4379,7 +4399,7 @@ version = "1.2.9"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"fast-math",
|
"fast-math",
|
||||||
"hex 0.4.2",
|
"hex 0.4.2",
|
||||||
"solana-sdk",
|
"solana-sdk 1.2.9",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@ -4394,7 +4414,7 @@ dependencies = [
|
|||||||
"reqwest",
|
"reqwest",
|
||||||
"serial_test",
|
"serial_test",
|
||||||
"serial_test_derive",
|
"serial_test_derive",
|
||||||
"solana-sdk",
|
"solana-sdk 1.2.9",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@ -4411,7 +4431,7 @@ dependencies = [
|
|||||||
"serde_derive",
|
"serde_derive",
|
||||||
"serde_json",
|
"serde_json",
|
||||||
"solana-logger",
|
"solana-logger",
|
||||||
"solana-sdk",
|
"solana-sdk 1.2.9",
|
||||||
"solana_libra_bytecode_verifier",
|
"solana_libra_bytecode_verifier",
|
||||||
"solana_libra_canonical_serialization",
|
"solana_libra_canonical_serialization",
|
||||||
"solana_libra_compiler",
|
"solana_libra_compiler",
|
||||||
@ -4464,7 +4484,7 @@ version = "1.2.9"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"log 0.4.8",
|
"log 0.4.8",
|
||||||
"solana-logger",
|
"solana-logger",
|
||||||
"solana-sdk",
|
"solana-sdk 1.2.9",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@ -4484,7 +4504,7 @@ dependencies = [
|
|||||||
"num-derive 0.3.0",
|
"num-derive 0.3.0",
|
||||||
"num-traits",
|
"num-traits",
|
||||||
"solana-runtime",
|
"solana-runtime",
|
||||||
"solana-sdk",
|
"solana-sdk 1.2.9",
|
||||||
"thiserror",
|
"thiserror",
|
||||||
]
|
]
|
||||||
|
|
||||||
@ -4506,7 +4526,7 @@ dependencies = [
|
|||||||
"solana-logger",
|
"solana-logger",
|
||||||
"solana-metrics",
|
"solana-metrics",
|
||||||
"solana-rayon-threadlimit",
|
"solana-rayon-threadlimit",
|
||||||
"solana-sdk",
|
"solana-sdk 1.2.9",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@ -4526,7 +4546,7 @@ dependencies = [
|
|||||||
"solana-metrics",
|
"solana-metrics",
|
||||||
"solana-net-utils",
|
"solana-net-utils",
|
||||||
"solana-notifier",
|
"solana-notifier",
|
||||||
"solana-sdk",
|
"solana-sdk 1.2.9",
|
||||||
"solana-stake-program",
|
"solana-stake-program",
|
||||||
"tar",
|
"tar",
|
||||||
]
|
]
|
||||||
@ -4552,7 +4572,7 @@ dependencies = [
|
|||||||
"num-traits",
|
"num-traits",
|
||||||
"parking_lot 0.10.2",
|
"parking_lot 0.10.2",
|
||||||
"semver",
|
"semver",
|
||||||
"solana-sdk",
|
"solana-sdk 1.2.9",
|
||||||
"thiserror",
|
"thiserror",
|
||||||
"url 2.1.1",
|
"url 2.1.1",
|
||||||
]
|
]
|
||||||
@ -4586,7 +4606,7 @@ dependencies = [
|
|||||||
"solana-metrics",
|
"solana-metrics",
|
||||||
"solana-noop-program",
|
"solana-noop-program",
|
||||||
"solana-rayon-threadlimit",
|
"solana-rayon-threadlimit",
|
||||||
"solana-sdk",
|
"solana-sdk 1.2.9",
|
||||||
"solana-stake-program",
|
"solana-stake-program",
|
||||||
"solana-vote-program",
|
"solana-vote-program",
|
||||||
"tempfile",
|
"tempfile",
|
||||||
@ -4601,6 +4621,30 @@ dependencies = [
|
|||||||
"serde",
|
"serde",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "solana-sdk"
|
||||||
|
version = "1.2.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "14b628fa500e0b83df3e96f7cc21dc998d8841a994f1c2109475273e6448afd4"
|
||||||
|
dependencies = [
|
||||||
|
"bincode",
|
||||||
|
"bs58 0.3.1",
|
||||||
|
"bv",
|
||||||
|
"hex 0.4.2",
|
||||||
|
"hmac",
|
||||||
|
"itertools 0.9.0",
|
||||||
|
"log 0.4.8",
|
||||||
|
"num-derive 0.3.0",
|
||||||
|
"num-traits",
|
||||||
|
"pbkdf2",
|
||||||
|
"serde",
|
||||||
|
"serde_bytes",
|
||||||
|
"serde_derive",
|
||||||
|
"sha2",
|
||||||
|
"solana-sdk-macro 1.2.4",
|
||||||
|
"thiserror",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "solana-sdk"
|
name = "solana-sdk"
|
||||||
version = "1.2.9"
|
version = "1.2.9"
|
||||||
@ -4630,11 +4674,23 @@ dependencies = [
|
|||||||
"sha2",
|
"sha2",
|
||||||
"solana-crate-features",
|
"solana-crate-features",
|
||||||
"solana-logger",
|
"solana-logger",
|
||||||
"solana-sdk-macro",
|
"solana-sdk-macro 1.2.9",
|
||||||
"thiserror",
|
"thiserror",
|
||||||
"tiny-bip39",
|
"tiny-bip39",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "solana-sdk-macro"
|
||||||
|
version = "1.2.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "da5f311e7735323eb0ad348c68170c2503a2c56cfa1a261646d8182b373fa670"
|
||||||
|
dependencies = [
|
||||||
|
"bs58 0.3.1",
|
||||||
|
"proc-macro2 1.0.18",
|
||||||
|
"quote 1.0.7",
|
||||||
|
"syn 1.0.33",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "solana-sdk-macro"
|
name = "solana-sdk-macro"
|
||||||
version = "1.2.9"
|
version = "1.2.9"
|
||||||
@ -4655,7 +4711,7 @@ dependencies = [
|
|||||||
"solana-client",
|
"solana-client",
|
||||||
"solana-remote-wallet",
|
"solana-remote-wallet",
|
||||||
"solana-runtime",
|
"solana-runtime",
|
||||||
"solana-sdk",
|
"solana-sdk 1.2.9",
|
||||||
"solana-stake-program",
|
"solana-stake-program",
|
||||||
]
|
]
|
||||||
|
|
||||||
@ -4677,7 +4733,7 @@ dependencies = [
|
|||||||
"solana-local-cluster",
|
"solana-local-cluster",
|
||||||
"solana-logger",
|
"solana-logger",
|
||||||
"solana-metrics",
|
"solana-metrics",
|
||||||
"solana-sdk",
|
"solana-sdk 1.2.9",
|
||||||
"solana-stake-program",
|
"solana-stake-program",
|
||||||
"solana-transaction-status",
|
"solana-transaction-status",
|
||||||
"solana-version",
|
"solana-version",
|
||||||
@ -4697,7 +4753,7 @@ dependencies = [
|
|||||||
"solana-logger",
|
"solana-logger",
|
||||||
"solana-metrics",
|
"solana-metrics",
|
||||||
"solana-notifier",
|
"solana-notifier",
|
||||||
"solana-sdk",
|
"solana-sdk 1.2.9",
|
||||||
"solana-stake-program",
|
"solana-stake-program",
|
||||||
"solana-transaction-status",
|
"solana-transaction-status",
|
||||||
]
|
]
|
||||||
@ -4715,7 +4771,7 @@ dependencies = [
|
|||||||
"solana-config-program",
|
"solana-config-program",
|
||||||
"solana-logger",
|
"solana-logger",
|
||||||
"solana-metrics",
|
"solana-metrics",
|
||||||
"solana-sdk",
|
"solana-sdk 1.2.9",
|
||||||
"solana-vote-program",
|
"solana-vote-program",
|
||||||
"thiserror",
|
"thiserror",
|
||||||
]
|
]
|
||||||
@ -4731,7 +4787,7 @@ dependencies = [
|
|||||||
"solana-measure",
|
"solana-measure",
|
||||||
"solana-metrics",
|
"solana-metrics",
|
||||||
"solana-perf",
|
"solana-perf",
|
||||||
"solana-sdk",
|
"solana-sdk 1.2.9",
|
||||||
"thiserror",
|
"thiserror",
|
||||||
]
|
]
|
||||||
|
|
||||||
@ -4770,7 +4826,7 @@ dependencies = [
|
|||||||
"solana-core",
|
"solana-core",
|
||||||
"solana-remote-wallet",
|
"solana-remote-wallet",
|
||||||
"solana-runtime",
|
"solana-runtime",
|
||||||
"solana-sdk",
|
"solana-sdk 1.2.9",
|
||||||
"solana-stake-program",
|
"solana-stake-program",
|
||||||
"solana-transaction-status",
|
"solana-transaction-status",
|
||||||
"tempfile",
|
"tempfile",
|
||||||
@ -4781,11 +4837,15 @@ dependencies = [
|
|||||||
name = "solana-transaction-status"
|
name = "solana-transaction-status"
|
||||||
version = "1.2.9"
|
version = "1.2.9"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
|
"Inflector",
|
||||||
"bincode",
|
"bincode",
|
||||||
"bs58 0.3.1",
|
"bs58 0.3.1",
|
||||||
|
"lazy_static",
|
||||||
"serde",
|
"serde",
|
||||||
"serde_derive",
|
"serde_derive",
|
||||||
"solana-sdk",
|
"serde_json",
|
||||||
|
"solana-sdk 1.2.9",
|
||||||
|
"spl-memo",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@ -4819,7 +4879,7 @@ dependencies = [
|
|||||||
"solana-net-utils",
|
"solana-net-utils",
|
||||||
"solana-perf",
|
"solana-perf",
|
||||||
"solana-runtime",
|
"solana-runtime",
|
||||||
"solana-sdk",
|
"solana-sdk 1.2.9",
|
||||||
"solana-version",
|
"solana-version",
|
||||||
"solana-vote-program",
|
"solana-vote-program",
|
||||||
"solana-vote-signer",
|
"solana-vote-signer",
|
||||||
@ -4831,7 +4891,7 @@ version = "1.2.9"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"serde",
|
"serde",
|
||||||
"serde_derive",
|
"serde_derive",
|
||||||
"solana-sdk",
|
"solana-sdk 1.2.9",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@ -4846,7 +4906,7 @@ dependencies = [
|
|||||||
"serde_derive",
|
"serde_derive",
|
||||||
"solana-config-program",
|
"solana-config-program",
|
||||||
"solana-runtime",
|
"solana-runtime",
|
||||||
"solana-sdk",
|
"solana-sdk 1.2.9",
|
||||||
"thiserror",
|
"thiserror",
|
||||||
]
|
]
|
||||||
|
|
||||||
@ -4861,7 +4921,7 @@ dependencies = [
|
|||||||
"serde",
|
"serde",
|
||||||
"serde_derive",
|
"serde_derive",
|
||||||
"solana-metrics",
|
"solana-metrics",
|
||||||
"solana-sdk",
|
"solana-sdk 1.2.9",
|
||||||
"thiserror",
|
"thiserror",
|
||||||
]
|
]
|
||||||
|
|
||||||
@ -4877,7 +4937,7 @@ dependencies = [
|
|||||||
"serde_json",
|
"serde_json",
|
||||||
"solana-clap-utils",
|
"solana-clap-utils",
|
||||||
"solana-metrics",
|
"solana-metrics",
|
||||||
"solana-sdk",
|
"solana-sdk 1.2.9",
|
||||||
"solana-version",
|
"solana-version",
|
||||||
]
|
]
|
||||||
|
|
||||||
@ -4895,7 +4955,7 @@ dependencies = [
|
|||||||
"solana-logger",
|
"solana-logger",
|
||||||
"solana-metrics",
|
"solana-metrics",
|
||||||
"solana-notifier",
|
"solana-notifier",
|
||||||
"solana-sdk",
|
"solana-sdk 1.2.9",
|
||||||
"solana-transaction-status",
|
"solana-transaction-status",
|
||||||
"solana-version",
|
"solana-version",
|
||||||
"solana-vote-program",
|
"solana-vote-program",
|
||||||
@ -5268,6 +5328,15 @@ version = "0.5.2"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "6e63cff320ae2c57904679ba7cb63280a3dc4613885beafb148ee7bf9aa9042d"
|
checksum = "6e63cff320ae2c57904679ba7cb63280a3dc4613885beafb148ee7bf9aa9042d"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "spl-memo"
|
||||||
|
version = "1.0.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "22e6b954ac8b1df3f0bbb6ad1f21607be304f3cc9914bb9107c44b2065c8479e"
|
||||||
|
dependencies = [
|
||||||
|
"solana-sdk 1.2.4",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "stable_deref_trait"
|
name = "stable_deref_trait"
|
||||||
version = "1.1.1"
|
version = "1.1.1"
|
||||||
|
@ -52,6 +52,7 @@ members = [
|
|||||||
"sys-tuner",
|
"sys-tuner",
|
||||||
"tokens",
|
"tokens",
|
||||||
"transaction-status",
|
"transaction-status",
|
||||||
|
"account-decoder",
|
||||||
"upload-perf",
|
"upload-perf",
|
||||||
"net-utils",
|
"net-utils",
|
||||||
"version",
|
"version",
|
||||||
|
25
account-decoder/Cargo.toml
Normal file
25
account-decoder/Cargo.toml
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
[package]
|
||||||
|
name = "solana-account-decoder"
|
||||||
|
version = "1.2.9"
|
||||||
|
description = "Solana account decoder"
|
||||||
|
authors = ["Solana Maintainers <maintainers@solana.foundation>"]
|
||||||
|
repository = "https://github.com/solana-labs/solana"
|
||||||
|
homepage = "https://solana.com/"
|
||||||
|
license = "Apache-2.0"
|
||||||
|
edition = "2018"
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
bincode = "1.2.1"
|
||||||
|
bs58 = "0.3.1"
|
||||||
|
Inflector = "0.11.4"
|
||||||
|
lazy_static = "1.4.0"
|
||||||
|
solana-sdk = { path = "../sdk", version = "1.2.9" }
|
||||||
|
solana-vote-program = { path = "../programs/vote", version = "1.2.9" }
|
||||||
|
spl-memo = "1.0.0"
|
||||||
|
serde = "1.0.112"
|
||||||
|
serde_derive = "1.0.103"
|
||||||
|
serde_json = "1.0.54"
|
||||||
|
thiserror = "1.0"
|
||||||
|
|
||||||
|
[package.metadata.docs.rs]
|
||||||
|
targets = ["x86_64-unknown-linux-gnu"]
|
80
account-decoder/src/lib.rs
Normal file
80
account-decoder/src/lib.rs
Normal file
@ -0,0 +1,80 @@
|
|||||||
|
#[macro_use]
|
||||||
|
extern crate lazy_static;
|
||||||
|
#[macro_use]
|
||||||
|
extern crate serde_derive;
|
||||||
|
|
||||||
|
pub mod parse_account_data;
|
||||||
|
pub mod parse_nonce;
|
||||||
|
pub mod parse_vote;
|
||||||
|
|
||||||
|
use crate::parse_account_data::parse_account_data;
|
||||||
|
use serde_json::Value;
|
||||||
|
use solana_sdk::{account::Account, clock::Epoch, pubkey::Pubkey};
|
||||||
|
use std::str::FromStr;
|
||||||
|
|
||||||
|
/// A duplicate representation of an Account for pretty JSON serialization
|
||||||
|
#[derive(Serialize, Deserialize, Clone, Debug)]
|
||||||
|
#[serde(rename_all = "camelCase")]
|
||||||
|
pub struct UiAccount {
|
||||||
|
pub lamports: u64,
|
||||||
|
pub data: UiAccountData,
|
||||||
|
pub owner: String,
|
||||||
|
pub executable: bool,
|
||||||
|
pub rent_epoch: Epoch,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
|
||||||
|
#[serde(rename_all = "camelCase", untagged)]
|
||||||
|
pub enum UiAccountData {
|
||||||
|
Binary(String),
|
||||||
|
Json(Value),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<Vec<u8>> for UiAccountData {
|
||||||
|
fn from(data: Vec<u8>) -> Self {
|
||||||
|
Self::Binary(bs58::encode(data).into_string())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq)]
|
||||||
|
#[serde(rename_all = "camelCase")]
|
||||||
|
pub enum UiAccountEncoding {
|
||||||
|
Binary,
|
||||||
|
JsonParsed,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl UiAccount {
|
||||||
|
pub fn encode(account: Account, encoding: UiAccountEncoding) -> Self {
|
||||||
|
let data = match encoding {
|
||||||
|
UiAccountEncoding::Binary => account.data.into(),
|
||||||
|
UiAccountEncoding::JsonParsed => {
|
||||||
|
if let Ok(parsed_data) = parse_account_data(&account.owner, &account.data) {
|
||||||
|
UiAccountData::Json(parsed_data)
|
||||||
|
} else {
|
||||||
|
account.data.into()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
UiAccount {
|
||||||
|
lamports: account.lamports,
|
||||||
|
data,
|
||||||
|
owner: account.owner.to_string(),
|
||||||
|
executable: account.executable,
|
||||||
|
rent_epoch: account.rent_epoch,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn decode(&self) -> Option<Account> {
|
||||||
|
let data = match &self.data {
|
||||||
|
UiAccountData::Json(_) => None,
|
||||||
|
UiAccountData::Binary(blob) => bs58::decode(blob).into_vec().ok(),
|
||||||
|
}?;
|
||||||
|
Some(Account {
|
||||||
|
lamports: self.lamports,
|
||||||
|
data,
|
||||||
|
owner: Pubkey::from_str(&self.owner).ok()?,
|
||||||
|
executable: self.executable,
|
||||||
|
rent_epoch: self.rent_epoch,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
80
account-decoder/src/parse_account_data.rs
Normal file
80
account-decoder/src/parse_account_data.rs
Normal file
@ -0,0 +1,80 @@
|
|||||||
|
use crate::{parse_nonce::parse_nonce, parse_vote::parse_vote};
|
||||||
|
use inflector::Inflector;
|
||||||
|
use serde_json::{json, Value};
|
||||||
|
use solana_sdk::{instruction::InstructionError, pubkey::Pubkey, system_program};
|
||||||
|
use std::{collections::HashMap, str::FromStr};
|
||||||
|
use thiserror::Error;
|
||||||
|
|
||||||
|
lazy_static! {
|
||||||
|
static ref SYSTEM_PROGRAM_ID: Pubkey =
|
||||||
|
Pubkey::from_str(&system_program::id().to_string()).unwrap();
|
||||||
|
static ref VOTE_PROGRAM_ID: Pubkey =
|
||||||
|
Pubkey::from_str(&solana_vote_program::id().to_string()).unwrap();
|
||||||
|
pub static ref PARSABLE_PROGRAM_IDS: HashMap<Pubkey, ParsableAccount> = {
|
||||||
|
let mut m = HashMap::new();
|
||||||
|
m.insert(*SYSTEM_PROGRAM_ID, ParsableAccount::Nonce);
|
||||||
|
m.insert(*VOTE_PROGRAM_ID, ParsableAccount::Vote);
|
||||||
|
m
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Error, Debug)]
|
||||||
|
pub enum ParseAccountError {
|
||||||
|
#[error("Program not parsable")]
|
||||||
|
ProgramNotParsable,
|
||||||
|
|
||||||
|
#[error("Instruction error")]
|
||||||
|
InstructionError(#[from] InstructionError),
|
||||||
|
|
||||||
|
#[error("Serde json error")]
|
||||||
|
SerdeJsonError(#[from] serde_json::error::Error),
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Serialize, Deserialize)]
|
||||||
|
#[serde(rename_all = "camelCase")]
|
||||||
|
pub enum ParsableAccount {
|
||||||
|
Nonce,
|
||||||
|
Vote,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn parse_account_data(program_id: &Pubkey, data: &[u8]) -> Result<Value, ParseAccountError> {
|
||||||
|
let program_name = PARSABLE_PROGRAM_IDS
|
||||||
|
.get(program_id)
|
||||||
|
.ok_or_else(|| ParseAccountError::ProgramNotParsable)?;
|
||||||
|
let parsed_json = match program_name {
|
||||||
|
ParsableAccount::Nonce => serde_json::to_value(parse_nonce(data)?)?,
|
||||||
|
ParsableAccount::Vote => serde_json::to_value(parse_vote(data)?)?,
|
||||||
|
};
|
||||||
|
Ok(json!({
|
||||||
|
format!("{:?}", program_name).to_kebab_case(): parsed_json
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod test {
|
||||||
|
use super::*;
|
||||||
|
use solana_sdk::nonce::{
|
||||||
|
state::{Data, Versions},
|
||||||
|
State,
|
||||||
|
};
|
||||||
|
use solana_vote_program::vote_state::{VoteState, VoteStateVersions};
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_parse_account_data() {
|
||||||
|
let other_program = Pubkey::new_rand();
|
||||||
|
let data = vec![0; 4];
|
||||||
|
assert!(parse_account_data(&other_program, &data).is_err());
|
||||||
|
|
||||||
|
let vote_state = VoteState::default();
|
||||||
|
let mut vote_account_data: Vec<u8> = vec![0; VoteState::size_of()];
|
||||||
|
let versioned = VoteStateVersions::Current(Box::new(vote_state));
|
||||||
|
VoteState::serialize(&versioned, &mut vote_account_data).unwrap();
|
||||||
|
let parsed = parse_account_data(&solana_vote_program::id(), &vote_account_data).unwrap();
|
||||||
|
assert!(parsed.as_object().unwrap().contains_key("vote"));
|
||||||
|
|
||||||
|
let nonce_data = Versions::new_current(State::Initialized(Data::default()));
|
||||||
|
let nonce_account_data = bincode::serialize(&nonce_data).unwrap();
|
||||||
|
let parsed = parse_account_data(&system_program::id(), &nonce_account_data).unwrap();
|
||||||
|
assert!(parsed.as_object().unwrap().contains_key("nonce"));
|
||||||
|
}
|
||||||
|
}
|
66
account-decoder/src/parse_nonce.rs
Normal file
66
account-decoder/src/parse_nonce.rs
Normal file
@ -0,0 +1,66 @@
|
|||||||
|
use crate::parse_account_data::ParseAccountError;
|
||||||
|
use solana_sdk::{
|
||||||
|
fee_calculator::FeeCalculator,
|
||||||
|
instruction::InstructionError,
|
||||||
|
nonce::{state::Versions, State},
|
||||||
|
};
|
||||||
|
|
||||||
|
pub fn parse_nonce(data: &[u8]) -> Result<UiNonceState, ParseAccountError> {
|
||||||
|
let nonce_state: Versions = bincode::deserialize(data)
|
||||||
|
.map_err(|_| ParseAccountError::from(InstructionError::InvalidAccountData))?;
|
||||||
|
let nonce_state = nonce_state.convert_to_current();
|
||||||
|
match nonce_state {
|
||||||
|
State::Uninitialized => Ok(UiNonceState::Uninitialized),
|
||||||
|
State::Initialized(data) => Ok(UiNonceState::Initialized(UiNonceData {
|
||||||
|
authority: data.authority.to_string(),
|
||||||
|
blockhash: data.blockhash.to_string(),
|
||||||
|
fee_calculator: data.fee_calculator,
|
||||||
|
})),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A duplicate representation of NonceState for pretty JSON serialization
|
||||||
|
#[derive(Debug, Serialize, Deserialize, PartialEq)]
|
||||||
|
#[serde(rename_all = "camelCase")]
|
||||||
|
pub enum UiNonceState {
|
||||||
|
Uninitialized,
|
||||||
|
Initialized(UiNonceData),
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Serialize, Deserialize, PartialEq)]
|
||||||
|
#[serde(rename_all = "camelCase")]
|
||||||
|
pub struct UiNonceData {
|
||||||
|
pub authority: String,
|
||||||
|
pub blockhash: String,
|
||||||
|
pub fee_calculator: FeeCalculator,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod test {
|
||||||
|
use super::*;
|
||||||
|
use solana_sdk::{
|
||||||
|
hash::Hash,
|
||||||
|
nonce::{
|
||||||
|
state::{Data, Versions},
|
||||||
|
State,
|
||||||
|
},
|
||||||
|
pubkey::Pubkey,
|
||||||
|
};
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_parse_nonce() {
|
||||||
|
let nonce_data = Versions::new_current(State::Initialized(Data::default()));
|
||||||
|
let nonce_account_data = bincode::serialize(&nonce_data).unwrap();
|
||||||
|
assert_eq!(
|
||||||
|
parse_nonce(&nonce_account_data).unwrap(),
|
||||||
|
UiNonceState::Initialized(UiNonceData {
|
||||||
|
authority: Pubkey::default().to_string(),
|
||||||
|
blockhash: Hash::default().to_string(),
|
||||||
|
fee_calculator: FeeCalculator::default(),
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
|
||||||
|
let bad_data = vec![0; 4];
|
||||||
|
assert!(parse_nonce(&bad_data).is_err());
|
||||||
|
}
|
||||||
|
}
|
134
account-decoder/src/parse_vote.rs
Normal file
134
account-decoder/src/parse_vote.rs
Normal file
@ -0,0 +1,134 @@
|
|||||||
|
use crate::parse_account_data::ParseAccountError;
|
||||||
|
use solana_sdk::{
|
||||||
|
clock::{Epoch, Slot},
|
||||||
|
pubkey::Pubkey,
|
||||||
|
};
|
||||||
|
use solana_vote_program::vote_state::{BlockTimestamp, Lockout, VoteState};
|
||||||
|
|
||||||
|
pub fn parse_vote(data: &[u8]) -> Result<UiVoteState, ParseAccountError> {
|
||||||
|
let mut vote_state = VoteState::deserialize(data).map_err(ParseAccountError::from)?;
|
||||||
|
let epoch_credits = vote_state
|
||||||
|
.epoch_credits()
|
||||||
|
.iter()
|
||||||
|
.map(|(epoch, credits, previous_credits)| UiEpochCredits {
|
||||||
|
epoch: *epoch,
|
||||||
|
credits: *credits,
|
||||||
|
previous_credits: *previous_credits,
|
||||||
|
})
|
||||||
|
.collect();
|
||||||
|
let votes = vote_state
|
||||||
|
.votes
|
||||||
|
.iter()
|
||||||
|
.map(|lockout| UiLockout {
|
||||||
|
slot: lockout.slot,
|
||||||
|
confirmation_count: lockout.confirmation_count,
|
||||||
|
})
|
||||||
|
.collect();
|
||||||
|
let authorized_voters = vote_state
|
||||||
|
.authorized_voters()
|
||||||
|
.iter()
|
||||||
|
.map(|(epoch, authorized_voter)| UiAuthorizedVoters {
|
||||||
|
epoch: *epoch,
|
||||||
|
authorized_voter: authorized_voter.to_string(),
|
||||||
|
})
|
||||||
|
.collect();
|
||||||
|
let prior_voters = vote_state
|
||||||
|
.prior_voters()
|
||||||
|
.buf()
|
||||||
|
.iter()
|
||||||
|
.filter(|(pubkey, _, _)| pubkey != &Pubkey::default())
|
||||||
|
.map(
|
||||||
|
|(authorized_pubkey, epoch_of_last_authorized_switch, target_epoch)| UiPriorVoters {
|
||||||
|
authorized_pubkey: authorized_pubkey.to_string(),
|
||||||
|
epoch_of_last_authorized_switch: *epoch_of_last_authorized_switch,
|
||||||
|
target_epoch: *target_epoch,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
.collect();
|
||||||
|
Ok(UiVoteState {
|
||||||
|
node_pubkey: vote_state.node_pubkey.to_string(),
|
||||||
|
authorized_withdrawer: vote_state.authorized_withdrawer.to_string(),
|
||||||
|
commission: vote_state.commission,
|
||||||
|
votes,
|
||||||
|
root_slot: vote_state.root_slot,
|
||||||
|
authorized_voters,
|
||||||
|
prior_voters,
|
||||||
|
epoch_credits,
|
||||||
|
last_timestamp: vote_state.last_timestamp,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A duplicate representation of VoteState for pretty JSON serialization
|
||||||
|
#[derive(Debug, Serialize, Deserialize, Default, PartialEq)]
|
||||||
|
#[serde(rename_all = "camelCase")]
|
||||||
|
pub struct UiVoteState {
|
||||||
|
node_pubkey: String,
|
||||||
|
authorized_withdrawer: String,
|
||||||
|
commission: u8,
|
||||||
|
votes: Vec<UiLockout>,
|
||||||
|
root_slot: Option<Slot>,
|
||||||
|
authorized_voters: Vec<UiAuthorizedVoters>,
|
||||||
|
prior_voters: Vec<UiPriorVoters>,
|
||||||
|
epoch_credits: Vec<UiEpochCredits>,
|
||||||
|
last_timestamp: BlockTimestamp,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Serialize, Deserialize, PartialEq)]
|
||||||
|
#[serde(rename_all = "camelCase")]
|
||||||
|
struct UiLockout {
|
||||||
|
slot: Slot,
|
||||||
|
confirmation_count: u32,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<&Lockout> for UiLockout {
|
||||||
|
fn from(lockout: &Lockout) -> Self {
|
||||||
|
Self {
|
||||||
|
slot: lockout.slot,
|
||||||
|
confirmation_count: lockout.confirmation_count,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Serialize, Deserialize, PartialEq)]
|
||||||
|
#[serde(rename_all = "camelCase")]
|
||||||
|
struct UiAuthorizedVoters {
|
||||||
|
epoch: Epoch,
|
||||||
|
authorized_voter: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Serialize, Deserialize, PartialEq)]
|
||||||
|
#[serde(rename_all = "camelCase")]
|
||||||
|
struct UiPriorVoters {
|
||||||
|
authorized_pubkey: String,
|
||||||
|
epoch_of_last_authorized_switch: Epoch,
|
||||||
|
target_epoch: Epoch,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Serialize, Deserialize, PartialEq)]
|
||||||
|
#[serde(rename_all = "camelCase")]
|
||||||
|
struct UiEpochCredits {
|
||||||
|
epoch: Epoch,
|
||||||
|
credits: u64,
|
||||||
|
previous_credits: u64,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod test {
|
||||||
|
use super::*;
|
||||||
|
use solana_vote_program::vote_state::VoteStateVersions;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_parse_vote() {
|
||||||
|
let vote_state = VoteState::default();
|
||||||
|
let mut vote_account_data: Vec<u8> = vec![0; VoteState::size_of()];
|
||||||
|
let versioned = VoteStateVersions::Current(Box::new(vote_state));
|
||||||
|
VoteState::serialize(&versioned, &mut vote_account_data).unwrap();
|
||||||
|
let mut expected_vote_state = UiVoteState::default();
|
||||||
|
expected_vote_state.node_pubkey = Pubkey::default().to_string();
|
||||||
|
expected_vote_state.authorized_withdrawer = Pubkey::default().to_string();
|
||||||
|
assert_eq!(parse_vote(&vote_account_data).unwrap(), expected_vote_state,);
|
||||||
|
|
||||||
|
let bad_data = vec![0; 4];
|
||||||
|
assert!(parse_vote(&bad_data).is_err());
|
||||||
|
}
|
||||||
|
}
|
@ -27,6 +27,7 @@ reqwest = { version = "0.10.4", default-features = false, features = ["blocking"
|
|||||||
serde = "1.0.110"
|
serde = "1.0.110"
|
||||||
serde_derive = "1.0.103"
|
serde_derive = "1.0.103"
|
||||||
serde_json = "1.0.53"
|
serde_json = "1.0.53"
|
||||||
|
solana-account-decoder = { path = "../account-decoder", version = "1.2.9" }
|
||||||
solana-budget-program = { path = "../programs/budget", version = "1.2.9" }
|
solana-budget-program = { path = "../programs/budget", version = "1.2.9" }
|
||||||
solana-clap-utils = { path = "../clap-utils", version = "1.2.9" }
|
solana-clap-utils = { path = "../clap-utils", version = "1.2.9" }
|
||||||
solana-cli-config = { path = "../cli-config", version = "1.2.9" }
|
solana-cli-config = { path = "../cli-config", version = "1.2.9" }
|
||||||
|
@ -15,6 +15,7 @@ use clap::{App, AppSettings, Arg, ArgMatches, SubCommand};
|
|||||||
use log::*;
|
use log::*;
|
||||||
use num_traits::FromPrimitive;
|
use num_traits::FromPrimitive;
|
||||||
use serde_json::{self, json, Value};
|
use serde_json::{self, json, Value};
|
||||||
|
use solana_account_decoder::{UiAccount, UiAccountEncoding};
|
||||||
use solana_budget_program::budget_instruction::{self, BudgetError};
|
use solana_budget_program::budget_instruction::{self, BudgetError};
|
||||||
use solana_clap_utils::{
|
use solana_clap_utils::{
|
||||||
commitment::{commitment_arg_with_default, COMMITMENT_ARG},
|
commitment::{commitment_arg_with_default, COMMITMENT_ARG},
|
||||||
@ -28,7 +29,7 @@ use solana_client::{
|
|||||||
client_error::{ClientError, ClientErrorKind, Result as ClientResult},
|
client_error::{ClientError, ClientErrorKind, Result as ClientResult},
|
||||||
rpc_client::RpcClient,
|
rpc_client::RpcClient,
|
||||||
rpc_config::{RpcLargestAccountsFilter, RpcSendTransactionConfig},
|
rpc_config::{RpcLargestAccountsFilter, RpcSendTransactionConfig},
|
||||||
rpc_response::{RpcAccount, RpcKeyedAccount},
|
rpc_response::RpcKeyedAccount,
|
||||||
};
|
};
|
||||||
#[cfg(not(test))]
|
#[cfg(not(test))]
|
||||||
use solana_faucet::faucet::request_airdrop_transaction;
|
use solana_faucet::faucet::request_airdrop_transaction;
|
||||||
@ -57,7 +58,7 @@ use solana_stake_program::{
|
|||||||
stake_instruction::LockupArgs,
|
stake_instruction::LockupArgs,
|
||||||
stake_state::{Lockup, StakeAuthorize},
|
stake_state::{Lockup, StakeAuthorize},
|
||||||
};
|
};
|
||||||
use solana_transaction_status::{EncodedTransaction, TransactionEncoding};
|
use solana_transaction_status::{EncodedTransaction, UiTransactionEncoding};
|
||||||
use solana_vote_program::vote_state::VoteAuthorize;
|
use solana_vote_program::vote_state::VoteAuthorize;
|
||||||
use std::{
|
use std::{
|
||||||
error,
|
error,
|
||||||
@ -1173,7 +1174,7 @@ fn process_confirm(
|
|||||||
if let Some(transaction_status) = status {
|
if let Some(transaction_status) = status {
|
||||||
if config.verbose {
|
if config.verbose {
|
||||||
match rpc_client
|
match rpc_client
|
||||||
.get_confirmed_transaction(signature, TransactionEncoding::Binary)
|
.get_confirmed_transaction(signature, UiTransactionEncoding::Binary)
|
||||||
{
|
{
|
||||||
Ok(confirmed_transaction) => {
|
Ok(confirmed_transaction) => {
|
||||||
println!(
|
println!(
|
||||||
@ -1226,7 +1227,7 @@ fn process_show_account(
|
|||||||
let cli_account = CliAccount {
|
let cli_account = CliAccount {
|
||||||
keyed_account: RpcKeyedAccount {
|
keyed_account: RpcKeyedAccount {
|
||||||
pubkey: account_pubkey.to_string(),
|
pubkey: account_pubkey.to_string(),
|
||||||
account: RpcAccount::encode(account),
|
account: UiAccount::encode(account, UiAccountEncoding::Binary),
|
||||||
},
|
},
|
||||||
use_lamports_unit,
|
use_lamports_unit,
|
||||||
};
|
};
|
||||||
|
@ -5,7 +5,7 @@ use solana_sdk::{
|
|||||||
hash::Hash, native_token::lamports_to_sol, program_utils::limited_deserialize,
|
hash::Hash, native_token::lamports_to_sol, program_utils::limited_deserialize,
|
||||||
transaction::Transaction,
|
transaction::Transaction,
|
||||||
};
|
};
|
||||||
use solana_transaction_status::RpcTransactionStatusMeta;
|
use solana_transaction_status::UiTransactionStatusMeta;
|
||||||
use std::{fmt, io};
|
use std::{fmt, io};
|
||||||
|
|
||||||
// Pretty print a "name value"
|
// Pretty print a "name value"
|
||||||
@ -68,7 +68,7 @@ pub fn println_signers(
|
|||||||
pub fn write_transaction<W: io::Write>(
|
pub fn write_transaction<W: io::Write>(
|
||||||
w: &mut W,
|
w: &mut W,
|
||||||
transaction: &Transaction,
|
transaction: &Transaction,
|
||||||
transaction_status: &Option<RpcTransactionStatusMeta>,
|
transaction_status: &Option<UiTransactionStatusMeta>,
|
||||||
prefix: &str,
|
prefix: &str,
|
||||||
) -> io::Result<()> {
|
) -> io::Result<()> {
|
||||||
let message = &transaction.message;
|
let message = &transaction.message;
|
||||||
@ -191,7 +191,7 @@ pub fn write_transaction<W: io::Write>(
|
|||||||
|
|
||||||
pub fn println_transaction(
|
pub fn println_transaction(
|
||||||
transaction: &Transaction,
|
transaction: &Transaction,
|
||||||
transaction_status: &Option<RpcTransactionStatusMeta>,
|
transaction_status: &Option<UiTransactionStatusMeta>,
|
||||||
prefix: &str,
|
prefix: &str,
|
||||||
) {
|
) {
|
||||||
let mut w = Vec::new();
|
let mut w = Vec::new();
|
||||||
|
@ -106,9 +106,10 @@ mod tests {
|
|||||||
use crate::{nonce::nonce_arg, offline::blockhash_query::BlockhashQuery};
|
use crate::{nonce::nonce_arg, offline::blockhash_query::BlockhashQuery};
|
||||||
use clap::App;
|
use clap::App;
|
||||||
use serde_json::{self, json, Value};
|
use serde_json::{self, json, Value};
|
||||||
|
use solana_account_decoder::{UiAccount, UiAccountEncoding};
|
||||||
use solana_client::{
|
use solana_client::{
|
||||||
rpc_request::RpcRequest,
|
rpc_request::RpcRequest,
|
||||||
rpc_response::{Response, RpcAccount, RpcFeeCalculator, RpcResponseContext},
|
rpc_response::{Response, RpcFeeCalculator, RpcResponseContext},
|
||||||
};
|
};
|
||||||
use solana_sdk::{
|
use solana_sdk::{
|
||||||
account::Account, fee_calculator::FeeCalculator, hash::hash, nonce, system_program,
|
account::Account, fee_calculator::FeeCalculator, hash::hash, nonce, system_program,
|
||||||
@ -344,7 +345,7 @@ mod tests {
|
|||||||
)
|
)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
let nonce_pubkey = Pubkey::new(&[4u8; 32]);
|
let nonce_pubkey = Pubkey::new(&[4u8; 32]);
|
||||||
let rpc_nonce_account = RpcAccount::encode(nonce_account);
|
let rpc_nonce_account = UiAccount::encode(nonce_account, UiAccountEncoding::Binary);
|
||||||
let get_account_response = json!(Response {
|
let get_account_response = json!(Response {
|
||||||
context: RpcResponseContext { slot: 1 },
|
context: RpcResponseContext { slot: 1 },
|
||||||
value: json!(Some(rpc_nonce_account)),
|
value: json!(Some(rpc_nonce_account)),
|
||||||
|
@ -19,9 +19,10 @@ reqwest = { version = "0.10.4", default-features = false, features = ["blocking"
|
|||||||
serde = "1.0.110"
|
serde = "1.0.110"
|
||||||
serde_derive = "1.0.103"
|
serde_derive = "1.0.103"
|
||||||
serde_json = "1.0.53"
|
serde_json = "1.0.53"
|
||||||
solana-transaction-status = { path = "../transaction-status", version = "1.2.9" }
|
solana-account-decoder = { path = "../account-decoder", version = "1.2.9" }
|
||||||
solana-net-utils = { path = "../net-utils", version = "1.2.9" }
|
solana-net-utils = { path = "../net-utils", version = "1.2.9" }
|
||||||
solana-sdk = { path = "../sdk", version = "1.2.9" }
|
solana-sdk = { path = "../sdk", version = "1.2.9" }
|
||||||
|
solana-transaction-status = { path = "../transaction-status", version = "1.2.9" }
|
||||||
solana-vote-program = { path = "../programs/vote", version = "1.2.9" }
|
solana-vote-program = { path = "../programs/vote", version = "1.2.9" }
|
||||||
thiserror = "1.0"
|
thiserror = "1.0"
|
||||||
tungstenite = "0.10.1"
|
tungstenite = "0.10.1"
|
||||||
|
@ -11,6 +11,7 @@ use bincode::serialize;
|
|||||||
use indicatif::{ProgressBar, ProgressStyle};
|
use indicatif::{ProgressBar, ProgressStyle};
|
||||||
use log::*;
|
use log::*;
|
||||||
use serde_json::{json, Value};
|
use serde_json::{json, Value};
|
||||||
|
use solana_account_decoder::UiAccount;
|
||||||
use solana_sdk::{
|
use solana_sdk::{
|
||||||
account::Account,
|
account::Account,
|
||||||
clock::{
|
clock::{
|
||||||
@ -28,7 +29,7 @@ use solana_sdk::{
|
|||||||
transaction::{self, Transaction},
|
transaction::{self, Transaction},
|
||||||
};
|
};
|
||||||
use solana_transaction_status::{
|
use solana_transaction_status::{
|
||||||
ConfirmedBlock, ConfirmedTransaction, TransactionEncoding, TransactionStatus,
|
ConfirmedBlock, ConfirmedTransaction, TransactionStatus, UiTransactionEncoding,
|
||||||
};
|
};
|
||||||
use solana_vote_program::vote_state::MAX_LOCKOUT_HISTORY;
|
use solana_vote_program::vote_state::MAX_LOCKOUT_HISTORY;
|
||||||
use std::{
|
use std::{
|
||||||
@ -238,13 +239,13 @@ impl RpcClient {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_confirmed_block(&self, slot: Slot) -> ClientResult<ConfirmedBlock> {
|
pub fn get_confirmed_block(&self, slot: Slot) -> ClientResult<ConfirmedBlock> {
|
||||||
self.get_confirmed_block_with_encoding(slot, TransactionEncoding::Json)
|
self.get_confirmed_block_with_encoding(slot, UiTransactionEncoding::Json)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_confirmed_block_with_encoding(
|
pub fn get_confirmed_block_with_encoding(
|
||||||
&self,
|
&self,
|
||||||
slot: Slot,
|
slot: Slot,
|
||||||
encoding: TransactionEncoding,
|
encoding: UiTransactionEncoding,
|
||||||
) -> ClientResult<ConfirmedBlock> {
|
) -> ClientResult<ConfirmedBlock> {
|
||||||
self.send(RpcRequest::GetConfirmedBlock, json!([slot, encoding]))
|
self.send(RpcRequest::GetConfirmedBlock, json!([slot, encoding]))
|
||||||
}
|
}
|
||||||
@ -285,7 +286,7 @@ impl RpcClient {
|
|||||||
pub fn get_confirmed_transaction(
|
pub fn get_confirmed_transaction(
|
||||||
&self,
|
&self,
|
||||||
signature: &Signature,
|
signature: &Signature,
|
||||||
encoding: TransactionEncoding,
|
encoding: UiTransactionEncoding,
|
||||||
) -> ClientResult<ConfirmedTransaction> {
|
) -> ClientResult<ConfirmedTransaction> {
|
||||||
self.send(
|
self.send(
|
||||||
RpcRequest::GetConfirmedTransaction,
|
RpcRequest::GetConfirmedTransaction,
|
||||||
@ -452,9 +453,9 @@ impl RpcClient {
|
|||||||
let Response {
|
let Response {
|
||||||
context,
|
context,
|
||||||
value: rpc_account,
|
value: rpc_account,
|
||||||
} = serde_json::from_value::<Response<Option<RpcAccount>>>(result_json)?;
|
} = serde_json::from_value::<Response<Option<UiAccount>>>(result_json)?;
|
||||||
trace!("Response account {:?} {:?}", pubkey, rpc_account);
|
trace!("Response account {:?} {:?}", pubkey, rpc_account);
|
||||||
let account = rpc_account.and_then(|rpc_account| rpc_account.decode().ok());
|
let account = rpc_account.and_then(|rpc_account| rpc_account.decode());
|
||||||
Ok(Response {
|
Ok(Response {
|
||||||
context,
|
context,
|
||||||
value: account,
|
value: account,
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
use crate::rpc_filter::RpcFilterType;
|
use crate::rpc_filter::RpcFilterType;
|
||||||
|
use solana_account_decoder::UiAccountEncoding;
|
||||||
use solana_sdk::{clock::Epoch, commitment_config::CommitmentConfig};
|
use solana_sdk::{clock::Epoch, commitment_config::CommitmentConfig};
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
|
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
|
||||||
@ -44,8 +45,16 @@ pub struct RpcStakeConfig {
|
|||||||
|
|
||||||
#[derive(Debug, Clone, Default, PartialEq, Serialize, Deserialize)]
|
#[derive(Debug, Clone, Default, PartialEq, Serialize, Deserialize)]
|
||||||
#[serde(rename_all = "camelCase")]
|
#[serde(rename_all = "camelCase")]
|
||||||
pub struct RpcProgramAccountsConfig {
|
pub struct RpcAccountInfoConfig {
|
||||||
pub filters: Option<Vec<RpcFilterType>>,
|
pub encoding: Option<UiAccountEncoding>,
|
||||||
#[serde(flatten)]
|
#[serde(flatten)]
|
||||||
pub commitment: Option<CommitmentConfig>,
|
pub commitment: Option<CommitmentConfig>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Default, PartialEq, Serialize, Deserialize)]
|
||||||
|
#[serde(rename_all = "camelCase")]
|
||||||
|
pub struct RpcProgramAccountsConfig {
|
||||||
|
pub filters: Option<Vec<RpcFilterType>>,
|
||||||
|
#[serde(flatten)]
|
||||||
|
pub account_config: RpcAccountInfoConfig,
|
||||||
|
}
|
||||||
|
@ -1,13 +1,12 @@
|
|||||||
use crate::{client_error, rpc_request::RpcError};
|
use crate::client_error;
|
||||||
|
use solana_account_decoder::UiAccount;
|
||||||
use solana_sdk::{
|
use solana_sdk::{
|
||||||
account::Account,
|
|
||||||
clock::{Epoch, Slot},
|
clock::{Epoch, Slot},
|
||||||
fee_calculator::{FeeCalculator, FeeRateGovernor},
|
fee_calculator::{FeeCalculator, FeeRateGovernor},
|
||||||
inflation::Inflation,
|
inflation::Inflation,
|
||||||
pubkey::Pubkey,
|
|
||||||
transaction::{Result, TransactionError},
|
transaction::{Result, TransactionError},
|
||||||
};
|
};
|
||||||
use std::{collections::HashMap, net::SocketAddr, str::FromStr};
|
use std::{collections::HashMap, net::SocketAddr};
|
||||||
|
|
||||||
pub type RpcResult<T> = client_error::Result<Response<T>>;
|
pub type RpcResult<T> = client_error::Result<Response<T>>;
|
||||||
|
|
||||||
@ -91,7 +90,7 @@ pub struct RpcInflationRate {
|
|||||||
#[serde(rename_all = "camelCase")]
|
#[serde(rename_all = "camelCase")]
|
||||||
pub struct RpcKeyedAccount {
|
pub struct RpcKeyedAccount {
|
||||||
pub pubkey: String,
|
pub pubkey: String,
|
||||||
pub account: RpcAccount,
|
pub account: UiAccount,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize, Clone, Debug)]
|
#[derive(Serialize, Deserialize, Clone, Debug)]
|
||||||
@ -100,43 +99,6 @@ pub struct RpcSignatureResult {
|
|||||||
pub err: Option<TransactionError>,
|
pub err: Option<TransactionError>,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A duplicate representation of a Message for pretty JSON serialization
|
|
||||||
#[derive(Serialize, Deserialize, Clone, Debug)]
|
|
||||||
#[serde(rename_all = "camelCase")]
|
|
||||||
pub struct RpcAccount {
|
|
||||||
pub lamports: u64,
|
|
||||||
pub data: String,
|
|
||||||
pub owner: String,
|
|
||||||
pub executable: bool,
|
|
||||||
pub rent_epoch: Epoch,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl RpcAccount {
|
|
||||||
pub fn encode(account: Account) -> Self {
|
|
||||||
RpcAccount {
|
|
||||||
lamports: account.lamports,
|
|
||||||
data: bs58::encode(account.data.clone()).into_string(),
|
|
||||||
owner: account.owner.to_string(),
|
|
||||||
executable: account.executable,
|
|
||||||
rent_epoch: account.rent_epoch,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn decode(&self) -> std::result::Result<Account, RpcError> {
|
|
||||||
Ok(Account {
|
|
||||||
lamports: self.lamports,
|
|
||||||
data: bs58::decode(self.data.clone()).into_vec().map_err(|_| {
|
|
||||||
RpcError::RpcRequestError("Could not parse encoded account data".to_string())
|
|
||||||
})?,
|
|
||||||
owner: Pubkey::from_str(&self.owner).map_err(|_| {
|
|
||||||
RpcError::RpcRequestError("Could not parse encoded account owner".to_string())
|
|
||||||
})?,
|
|
||||||
executable: self.executable,
|
|
||||||
rent_epoch: self.rent_epoch,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize, Clone, Debug)]
|
#[derive(Serialize, Deserialize, Clone, Debug)]
|
||||||
pub struct RpcContactInfo {
|
pub struct RpcContactInfo {
|
||||||
/// Pubkey of the node as a base-58 string
|
/// Pubkey of the node as a base-58 string
|
||||||
|
@ -42,11 +42,11 @@ regex = "1.3.7"
|
|||||||
serde = "1.0.110"
|
serde = "1.0.110"
|
||||||
serde_derive = "1.0.103"
|
serde_derive = "1.0.103"
|
||||||
serde_json = "1.0.53"
|
serde_json = "1.0.53"
|
||||||
|
solana-account-decoder = { path = "../account-decoder", version = "1.2.9" }
|
||||||
solana-bpf-loader-program = { path = "../programs/bpf_loader", version = "1.2.9" }
|
solana-bpf-loader-program = { path = "../programs/bpf_loader", version = "1.2.9" }
|
||||||
solana-budget-program = { path = "../programs/budget", version = "1.2.9" }
|
solana-budget-program = { path = "../programs/budget", version = "1.2.9" }
|
||||||
solana-clap-utils = { path = "../clap-utils", version = "1.2.9" }
|
solana-clap-utils = { path = "../clap-utils", version = "1.2.9" }
|
||||||
solana-client = { path = "../client", version = "1.2.9" }
|
solana-client = { path = "../client", version = "1.2.9" }
|
||||||
solana-transaction-status = { path = "../transaction-status", version = "1.2.9" }
|
|
||||||
solana-faucet = { path = "../faucet", version = "1.2.9" }
|
solana-faucet = { path = "../faucet", version = "1.2.9" }
|
||||||
solana-genesis-programs = { path = "../genesis-programs", version = "1.2.9" }
|
solana-genesis-programs = { path = "../genesis-programs", version = "1.2.9" }
|
||||||
solana-ledger = { path = "../ledger", version = "1.2.9" }
|
solana-ledger = { path = "../ledger", version = "1.2.9" }
|
||||||
@ -60,10 +60,11 @@ solana-runtime = { path = "../runtime", version = "1.2.9" }
|
|||||||
solana-sdk = { path = "../sdk", version = "1.2.9" }
|
solana-sdk = { path = "../sdk", version = "1.2.9" }
|
||||||
solana-stake-program = { path = "../programs/stake", version = "1.2.9" }
|
solana-stake-program = { path = "../programs/stake", version = "1.2.9" }
|
||||||
solana-streamer = { path = "../streamer", version = "1.2.9" }
|
solana-streamer = { path = "../streamer", version = "1.2.9" }
|
||||||
|
solana-sys-tuner = { path = "../sys-tuner", version = "1.2.9" }
|
||||||
|
solana-transaction-status = { path = "../transaction-status", version = "1.2.9" }
|
||||||
solana-version = { path = "../version", version = "1.2.9" }
|
solana-version = { path = "../version", version = "1.2.9" }
|
||||||
solana-vote-program = { path = "../programs/vote", version = "1.2.9" }
|
solana-vote-program = { path = "../programs/vote", version = "1.2.9" }
|
||||||
solana-vote-signer = { path = "../vote-signer", version = "1.2.9" }
|
solana-vote-signer = { path = "../vote-signer", version = "1.2.9" }
|
||||||
solana-sys-tuner = { path = "../sys-tuner", version = "1.2.9" }
|
|
||||||
tempfile = "3.1.0"
|
tempfile = "3.1.0"
|
||||||
thiserror = "1.0"
|
thiserror = "1.0"
|
||||||
tokio = "0.1"
|
tokio = "0.1"
|
||||||
|
@ -13,6 +13,7 @@ use crate::{
|
|||||||
use bincode::serialize;
|
use bincode::serialize;
|
||||||
use jsonrpc_core::{Error, Metadata, Result};
|
use jsonrpc_core::{Error, Metadata, Result};
|
||||||
use jsonrpc_derive::rpc;
|
use jsonrpc_derive::rpc;
|
||||||
|
use solana_account_decoder::{UiAccount, UiAccountEncoding};
|
||||||
use solana_client::{
|
use solana_client::{
|
||||||
rpc_config::*,
|
rpc_config::*,
|
||||||
rpc_filter::RpcFilterType,
|
rpc_filter::RpcFilterType,
|
||||||
@ -45,7 +46,7 @@ use solana_sdk::{
|
|||||||
};
|
};
|
||||||
use solana_stake_program::stake_state::StakeState;
|
use solana_stake_program::stake_state::StakeState;
|
||||||
use solana_transaction_status::{
|
use solana_transaction_status::{
|
||||||
ConfirmedBlock, ConfirmedTransaction, TransactionEncoding, TransactionStatus,
|
ConfirmedBlock, ConfirmedTransaction, TransactionStatus, UiTransactionEncoding,
|
||||||
};
|
};
|
||||||
use solana_vote_program::vote_state::{VoteState, MAX_LOCKOUT_HISTORY};
|
use solana_vote_program::vote_state::{VoteState, MAX_LOCKOUT_HISTORY};
|
||||||
use std::{
|
use std::{
|
||||||
@ -160,10 +161,16 @@ impl JsonRpcRequestProcessor {
|
|||||||
pub fn get_account_info(
|
pub fn get_account_info(
|
||||||
&self,
|
&self,
|
||||||
pubkey: &Pubkey,
|
pubkey: &Pubkey,
|
||||||
commitment: Option<CommitmentConfig>,
|
config: Option<RpcAccountInfoConfig>,
|
||||||
) -> Result<RpcResponse<Option<RpcAccount>>> {
|
) -> Result<RpcResponse<Option<UiAccount>>> {
|
||||||
let bank = self.bank(commitment)?;
|
let config = config.unwrap_or_default();
|
||||||
new_response(&bank, bank.get_account(pubkey).map(RpcAccount::encode))
|
let bank = self.bank(config.commitment)?;
|
||||||
|
let encoding = config.encoding.unwrap_or(UiAccountEncoding::Binary);
|
||||||
|
new_response(
|
||||||
|
&bank,
|
||||||
|
bank.get_account(pubkey)
|
||||||
|
.map(|account| UiAccount::encode(account, encoding)),
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_minimum_balance_for_rent_exemption(
|
pub fn get_minimum_balance_for_rent_exemption(
|
||||||
@ -179,11 +186,13 @@ impl JsonRpcRequestProcessor {
|
|||||||
pub fn get_program_accounts(
|
pub fn get_program_accounts(
|
||||||
&self,
|
&self,
|
||||||
program_id: &Pubkey,
|
program_id: &Pubkey,
|
||||||
commitment: Option<CommitmentConfig>,
|
config: Option<RpcAccountInfoConfig>,
|
||||||
filters: Vec<RpcFilterType>,
|
filters: Vec<RpcFilterType>,
|
||||||
) -> Result<Vec<RpcKeyedAccount>> {
|
) -> Result<Vec<RpcKeyedAccount>> {
|
||||||
Ok(self
|
let config = config.unwrap_or_default();
|
||||||
.bank(commitment)?
|
let bank = self.bank(config.commitment)?;
|
||||||
|
let encoding = config.encoding.unwrap_or(UiAccountEncoding::Binary);
|
||||||
|
Ok(bank
|
||||||
.get_program_accounts(Some(&program_id))
|
.get_program_accounts(Some(&program_id))
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.filter(|(_, account)| {
|
.filter(|(_, account)| {
|
||||||
@ -194,7 +203,7 @@ impl JsonRpcRequestProcessor {
|
|||||||
})
|
})
|
||||||
.map(|(pubkey, account)| RpcKeyedAccount {
|
.map(|(pubkey, account)| RpcKeyedAccount {
|
||||||
pubkey: pubkey.to_string(),
|
pubkey: pubkey.to_string(),
|
||||||
account: RpcAccount::encode(account),
|
account: UiAccount::encode(account, encoding.clone()),
|
||||||
})
|
})
|
||||||
.collect())
|
.collect())
|
||||||
}
|
}
|
||||||
@ -493,7 +502,7 @@ impl JsonRpcRequestProcessor {
|
|||||||
pub fn get_confirmed_block(
|
pub fn get_confirmed_block(
|
||||||
&self,
|
&self,
|
||||||
slot: Slot,
|
slot: Slot,
|
||||||
encoding: Option<TransactionEncoding>,
|
encoding: Option<UiTransactionEncoding>,
|
||||||
) -> Result<Option<ConfirmedBlock>> {
|
) -> Result<Option<ConfirmedBlock>> {
|
||||||
if self.config.enable_rpc_transaction_history
|
if self.config.enable_rpc_transaction_history
|
||||||
&& slot
|
&& slot
|
||||||
@ -662,7 +671,7 @@ impl JsonRpcRequestProcessor {
|
|||||||
pub fn get_confirmed_transaction(
|
pub fn get_confirmed_transaction(
|
||||||
&self,
|
&self,
|
||||||
signature: Signature,
|
signature: Signature,
|
||||||
encoding: Option<TransactionEncoding>,
|
encoding: Option<UiTransactionEncoding>,
|
||||||
) -> Result<Option<ConfirmedTransaction>> {
|
) -> Result<Option<ConfirmedTransaction>> {
|
||||||
if self.config.enable_rpc_transaction_history {
|
if self.config.enable_rpc_transaction_history {
|
||||||
Ok(self
|
Ok(self
|
||||||
@ -847,8 +856,8 @@ pub trait RpcSol {
|
|||||||
&self,
|
&self,
|
||||||
meta: Self::Metadata,
|
meta: Self::Metadata,
|
||||||
pubkey_str: String,
|
pubkey_str: String,
|
||||||
commitment: Option<CommitmentConfig>,
|
config: Option<RpcAccountInfoConfig>,
|
||||||
) -> Result<RpcResponse<Option<RpcAccount>>>;
|
) -> Result<RpcResponse<Option<UiAccount>>>;
|
||||||
|
|
||||||
#[rpc(meta, name = "getProgramAccounts")]
|
#[rpc(meta, name = "getProgramAccounts")]
|
||||||
fn get_program_accounts(
|
fn get_program_accounts(
|
||||||
@ -1042,7 +1051,7 @@ pub trait RpcSol {
|
|||||||
&self,
|
&self,
|
||||||
meta: Self::Metadata,
|
meta: Self::Metadata,
|
||||||
slot: Slot,
|
slot: Slot,
|
||||||
encoding: Option<TransactionEncoding>,
|
encoding: Option<UiTransactionEncoding>,
|
||||||
) -> Result<Option<ConfirmedBlock>>;
|
) -> Result<Option<ConfirmedBlock>>;
|
||||||
|
|
||||||
#[rpc(meta, name = "getBlockTime")]
|
#[rpc(meta, name = "getBlockTime")]
|
||||||
@ -1061,7 +1070,7 @@ pub trait RpcSol {
|
|||||||
&self,
|
&self,
|
||||||
meta: Self::Metadata,
|
meta: Self::Metadata,
|
||||||
signature_str: String,
|
signature_str: String,
|
||||||
encoding: Option<TransactionEncoding>,
|
encoding: Option<UiTransactionEncoding>,
|
||||||
) -> Result<Option<ConfirmedTransaction>>;
|
) -> Result<Option<ConfirmedTransaction>>;
|
||||||
|
|
||||||
#[rpc(meta, name = "getConfirmedSignaturesForAddress")]
|
#[rpc(meta, name = "getConfirmedSignaturesForAddress")]
|
||||||
@ -1104,11 +1113,11 @@ impl RpcSol for RpcSolImpl {
|
|||||||
&self,
|
&self,
|
||||||
meta: Self::Metadata,
|
meta: Self::Metadata,
|
||||||
pubkey_str: String,
|
pubkey_str: String,
|
||||||
commitment: Option<CommitmentConfig>,
|
config: Option<RpcAccountInfoConfig>,
|
||||||
) -> Result<RpcResponse<Option<RpcAccount>>> {
|
) -> Result<RpcResponse<Option<UiAccount>>> {
|
||||||
debug!("get_account_info rpc request received: {:?}", pubkey_str);
|
debug!("get_account_info rpc request received: {:?}", pubkey_str);
|
||||||
let pubkey = verify_pubkey(pubkey_str)?;
|
let pubkey = verify_pubkey(pubkey_str)?;
|
||||||
meta.get_account_info(&pubkey, commitment)
|
meta.get_account_info(&pubkey, config)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_minimum_balance_for_rent_exemption(
|
fn get_minimum_balance_for_rent_exemption(
|
||||||
@ -1135,15 +1144,18 @@ impl RpcSol for RpcSolImpl {
|
|||||||
program_id_str
|
program_id_str
|
||||||
);
|
);
|
||||||
let program_id = verify_pubkey(program_id_str)?;
|
let program_id = verify_pubkey(program_id_str)?;
|
||||||
let (commitment, filters) = if let Some(config) = config {
|
let (config, filters) = if let Some(config) = config {
|
||||||
(config.commitment, config.filters.unwrap_or_default())
|
(
|
||||||
|
Some(config.account_config),
|
||||||
|
config.filters.unwrap_or_default(),
|
||||||
|
)
|
||||||
} else {
|
} else {
|
||||||
(None, vec![])
|
(None, vec![])
|
||||||
};
|
};
|
||||||
for filter in &filters {
|
for filter in &filters {
|
||||||
verify_filter(filter)?;
|
verify_filter(filter)?;
|
||||||
}
|
}
|
||||||
meta.get_program_accounts(&program_id, commitment, filters)
|
meta.get_program_accounts(&program_id, config, filters)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_inflation_governor(
|
fn get_inflation_governor(
|
||||||
@ -1548,7 +1560,7 @@ impl RpcSol for RpcSolImpl {
|
|||||||
&self,
|
&self,
|
||||||
meta: Self::Metadata,
|
meta: Self::Metadata,
|
||||||
slot: Slot,
|
slot: Slot,
|
||||||
encoding: Option<TransactionEncoding>,
|
encoding: Option<UiTransactionEncoding>,
|
||||||
) -> Result<Option<ConfirmedBlock>> {
|
) -> Result<Option<ConfirmedBlock>> {
|
||||||
meta.get_confirmed_block(slot, encoding)
|
meta.get_confirmed_block(slot, encoding)
|
||||||
}
|
}
|
||||||
@ -1570,7 +1582,7 @@ impl RpcSol for RpcSolImpl {
|
|||||||
&self,
|
&self,
|
||||||
meta: Self::Metadata,
|
meta: Self::Metadata,
|
||||||
signature_str: String,
|
signature_str: String,
|
||||||
encoding: Option<TransactionEncoding>,
|
encoding: Option<UiTransactionEncoding>,
|
||||||
) -> Result<Option<ConfirmedTransaction>> {
|
) -> Result<Option<ConfirmedTransaction>> {
|
||||||
let signature = verify_signature(&signature_str)?;
|
let signature = verify_signature(&signature_str)?;
|
||||||
meta.get_confirmed_transaction(signature, encoding)
|
meta.get_confirmed_transaction(signature, encoding)
|
||||||
@ -1679,7 +1691,7 @@ pub mod tests {
|
|||||||
system_instruction, system_program, system_transaction,
|
system_instruction, system_program, system_transaction,
|
||||||
transaction::{self, TransactionError},
|
transaction::{self, TransactionError},
|
||||||
};
|
};
|
||||||
use solana_transaction_status::{EncodedTransaction, TransactionWithStatusMeta};
|
use solana_transaction_status::{EncodedTransaction, TransactionWithStatusMeta, UiMessage};
|
||||||
use solana_vote_program::{
|
use solana_vote_program::{
|
||||||
vote_instruction,
|
vote_instruction,
|
||||||
vote_state::{Vote, VoteInit, MAX_LOCKOUT_HISTORY},
|
vote_state::{Vote, VoteInit, MAX_LOCKOUT_HISTORY},
|
||||||
@ -3416,7 +3428,11 @@ pub mod tests {
|
|||||||
if let EncodedTransaction::Json(transaction) = transaction {
|
if let EncodedTransaction::Json(transaction) = transaction {
|
||||||
if transaction.signatures[0] == confirmed_block_signatures[0].to_string() {
|
if transaction.signatures[0] == confirmed_block_signatures[0].to_string() {
|
||||||
let meta = meta.unwrap();
|
let meta = meta.unwrap();
|
||||||
assert_eq!(transaction.message.recent_blockhash, blockhash.to_string());
|
let transaction_recent_blockhash = match transaction.message {
|
||||||
|
UiMessage::Parsed(message) => message.recent_blockhash,
|
||||||
|
UiMessage::Raw(message) => message.recent_blockhash,
|
||||||
|
};
|
||||||
|
assert_eq!(transaction_recent_blockhash, blockhash.to_string());
|
||||||
assert_eq!(meta.status, Ok(()));
|
assert_eq!(meta.status, Ok(()));
|
||||||
assert_eq!(meta.err, None);
|
assert_eq!(meta.err, None);
|
||||||
} else if transaction.signatures[0] == confirmed_block_signatures[1].to_string() {
|
} else if transaction.signatures[0] == confirmed_block_signatures[1].to_string() {
|
||||||
|
@ -4,9 +4,8 @@ use crate::rpc_subscriptions::{RpcSubscriptions, RpcVote, SlotInfo};
|
|||||||
use jsonrpc_core::{Error, ErrorCode, Result};
|
use jsonrpc_core::{Error, ErrorCode, Result};
|
||||||
use jsonrpc_derive::rpc;
|
use jsonrpc_derive::rpc;
|
||||||
use jsonrpc_pubsub::{typed::Subscriber, Session, SubscriptionId};
|
use jsonrpc_pubsub::{typed::Subscriber, Session, SubscriptionId};
|
||||||
use solana_client::rpc_response::{
|
use solana_account_decoder::UiAccount;
|
||||||
Response as RpcResponse, RpcAccount, RpcKeyedAccount, RpcSignatureResult,
|
use solana_client::rpc_response::{Response as RpcResponse, RpcKeyedAccount, RpcSignatureResult};
|
||||||
};
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
use solana_ledger::{bank_forks::BankForks, blockstore::Blockstore};
|
use solana_ledger::{bank_forks::BankForks, blockstore::Blockstore};
|
||||||
use solana_sdk::{
|
use solana_sdk::{
|
||||||
@ -37,7 +36,7 @@ pub trait RpcSolPubSub {
|
|||||||
fn account_subscribe(
|
fn account_subscribe(
|
||||||
&self,
|
&self,
|
||||||
meta: Self::Metadata,
|
meta: Self::Metadata,
|
||||||
subscriber: Subscriber<RpcResponse<RpcAccount>>,
|
subscriber: Subscriber<RpcResponse<UiAccount>>,
|
||||||
pubkey_str: String,
|
pubkey_str: String,
|
||||||
commitment: Option<CommitmentConfig>,
|
commitment: Option<CommitmentConfig>,
|
||||||
);
|
);
|
||||||
@ -177,7 +176,7 @@ impl RpcSolPubSub for RpcSolPubSubImpl {
|
|||||||
fn account_subscribe(
|
fn account_subscribe(
|
||||||
&self,
|
&self,
|
||||||
_meta: Self::Metadata,
|
_meta: Self::Metadata,
|
||||||
subscriber: Subscriber<RpcResponse<RpcAccount>>,
|
subscriber: Subscriber<RpcResponse<UiAccount>>,
|
||||||
pubkey_str: String,
|
pubkey_str: String,
|
||||||
commitment: Option<CommitmentConfig>,
|
commitment: Option<CommitmentConfig>,
|
||||||
) {
|
) {
|
||||||
|
@ -8,8 +8,9 @@ use jsonrpc_pubsub::{
|
|||||||
SubscriptionId,
|
SubscriptionId,
|
||||||
};
|
};
|
||||||
use serde::Serialize;
|
use serde::Serialize;
|
||||||
|
use solana_account_decoder::{UiAccount, UiAccountEncoding};
|
||||||
use solana_client::rpc_response::{
|
use solana_client::rpc_response::{
|
||||||
Response, RpcAccount, RpcKeyedAccount, RpcResponseContext, RpcSignatureResult,
|
Response, RpcKeyedAccount, RpcResponseContext, RpcSignatureResult,
|
||||||
};
|
};
|
||||||
use solana_ledger::{bank_forks::BankForks, blockstore::Blockstore};
|
use solana_ledger::{bank_forks::BankForks, blockstore::Blockstore};
|
||||||
use solana_runtime::bank::Bank;
|
use solana_runtime::bank::Bank;
|
||||||
@ -92,7 +93,7 @@ struct SubscriptionData<S> {
|
|||||||
last_notified_slot: RwLock<Slot>,
|
last_notified_slot: RwLock<Slot>,
|
||||||
}
|
}
|
||||||
type RpcAccountSubscriptions =
|
type RpcAccountSubscriptions =
|
||||||
RwLock<HashMap<Pubkey, HashMap<SubscriptionId, SubscriptionData<Response<RpcAccount>>>>>;
|
RwLock<HashMap<Pubkey, HashMap<SubscriptionId, SubscriptionData<Response<UiAccount>>>>>;
|
||||||
type RpcProgramSubscriptions =
|
type RpcProgramSubscriptions =
|
||||||
RwLock<HashMap<Pubkey, HashMap<SubscriptionId, SubscriptionData<Response<RpcKeyedAccount>>>>>;
|
RwLock<HashMap<Pubkey, HashMap<SubscriptionId, SubscriptionData<Response<RpcKeyedAccount>>>>>;
|
||||||
type RpcSignatureSubscriptions = RwLock<
|
type RpcSignatureSubscriptions = RwLock<
|
||||||
@ -227,12 +228,18 @@ impl RpcNotifier {
|
|||||||
fn filter_account_result(
|
fn filter_account_result(
|
||||||
result: Option<(Account, Slot)>,
|
result: Option<(Account, Slot)>,
|
||||||
last_notified_slot: Slot,
|
last_notified_slot: Slot,
|
||||||
) -> (Box<dyn Iterator<Item = RpcAccount>>, Slot) {
|
) -> (Box<dyn Iterator<Item = UiAccount>>, Slot) {
|
||||||
if let Some((account, fork)) = result {
|
if let Some((account, fork)) = result {
|
||||||
// If fork < last_notified_slot this means that we last notified for a fork
|
// If fork < last_notified_slot this means that we last notified for a fork
|
||||||
// and should notify that the account state has been reverted.
|
// and should notify that the account state has been reverted.
|
||||||
if fork != last_notified_slot {
|
if fork != last_notified_slot {
|
||||||
return (Box::new(iter::once(RpcAccount::encode(account))), fork);
|
return (
|
||||||
|
Box::new(iter::once(UiAccount::encode(
|
||||||
|
account,
|
||||||
|
UiAccountEncoding::Binary,
|
||||||
|
))),
|
||||||
|
fork,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
(Box::new(iter::empty()), last_notified_slot)
|
(Box::new(iter::empty()), last_notified_slot)
|
||||||
@ -262,7 +269,7 @@ fn filter_program_results(
|
|||||||
.into_iter()
|
.into_iter()
|
||||||
.map(|(pubkey, account)| RpcKeyedAccount {
|
.map(|(pubkey, account)| RpcKeyedAccount {
|
||||||
pubkey: pubkey.to_string(),
|
pubkey: pubkey.to_string(),
|
||||||
account: RpcAccount::encode(account),
|
account: UiAccount::encode(account, UiAccountEncoding::Binary),
|
||||||
}),
|
}),
|
||||||
),
|
),
|
||||||
last_notified_slot,
|
last_notified_slot,
|
||||||
@ -456,7 +463,7 @@ impl RpcSubscriptions {
|
|||||||
pubkey: Pubkey,
|
pubkey: Pubkey,
|
||||||
commitment: Option<CommitmentConfig>,
|
commitment: Option<CommitmentConfig>,
|
||||||
sub_id: SubscriptionId,
|
sub_id: SubscriptionId,
|
||||||
subscriber: Subscriber<Response<RpcAccount>>,
|
subscriber: Subscriber<Response<UiAccount>>,
|
||||||
) {
|
) {
|
||||||
let commitment_level = commitment
|
let commitment_level = commitment
|
||||||
.unwrap_or_else(CommitmentConfig::single)
|
.unwrap_or_else(CommitmentConfig::single)
|
||||||
|
@ -7,9 +7,10 @@ use jsonrpc_core_client::transports::ws;
|
|||||||
use log::*;
|
use log::*;
|
||||||
use reqwest::{self, header::CONTENT_TYPE};
|
use reqwest::{self, header::CONTENT_TYPE};
|
||||||
use serde_json::{json, Value};
|
use serde_json::{json, Value};
|
||||||
|
use solana_account_decoder::UiAccount;
|
||||||
use solana_client::{
|
use solana_client::{
|
||||||
rpc_client::{get_rpc_request_str, RpcClient},
|
rpc_client::{get_rpc_request_str, RpcClient},
|
||||||
rpc_response::{Response, RpcAccount, RpcSignatureResult},
|
rpc_response::{Response, RpcSignatureResult},
|
||||||
};
|
};
|
||||||
use solana_core::contact_info::ContactInfo;
|
use solana_core::contact_info::ContactInfo;
|
||||||
use solana_core::{rpc_pubsub::gen_client::Client as PubsubClient, validator::TestValidator};
|
use solana_core::{rpc_pubsub::gen_client::Client as PubsubClient, validator::TestValidator};
|
||||||
@ -172,7 +173,7 @@ fn test_rpc_subscriptions() {
|
|||||||
// Track when subscriptions are ready
|
// Track when subscriptions are ready
|
||||||
let (ready_sender, ready_receiver) = channel::<()>();
|
let (ready_sender, ready_receiver) = channel::<()>();
|
||||||
// Track account notifications are received
|
// Track account notifications are received
|
||||||
let (account_sender, account_receiver) = channel::<Response<RpcAccount>>();
|
let (account_sender, account_receiver) = channel::<Response<UiAccount>>();
|
||||||
// Track when status notifications are received
|
// Track when status notifications are received
|
||||||
let (status_sender, status_receiver) = channel::<(String, Response<RpcSignatureResult>)>();
|
let (status_sender, status_receiver) = channel::<(String, Response<RpcSignatureResult>)>();
|
||||||
|
|
||||||
|
@ -138,7 +138,10 @@ Returns all information associated with the account of provided Pubkey
|
|||||||
#### Parameters:
|
#### Parameters:
|
||||||
|
|
||||||
* `<string>` - Pubkey of account to query, as base-58 encoded string
|
* `<string>` - Pubkey of account to query, as base-58 encoded string
|
||||||
* `<object>` - (optional) [Commitment](jsonrpc-api.md#configuring-state-commitment)
|
* `<object>` - (optional) Configuration object containing the following optional fields:
|
||||||
|
* (optional) [Commitment](jsonrpc-api.md#configuring-state-commitment)
|
||||||
|
* (optional) `encoding: <string>` - encoding for Account data, either "binary" or jsonParsed". If parameter not provided, the default encoding is binary.
|
||||||
|
Parsed-JSON encoding attempts to use program-specific state parsers to return more human-readable and explicit account state data. If parsed-JSON is requested but a parser cannot be found, the field falls back to binary encoding, detectable when the `data` field is type `<string>`.
|
||||||
|
|
||||||
#### Results:
|
#### Results:
|
||||||
|
|
||||||
@ -148,7 +151,7 @@ The result will be an RpcResponse JSON object with `value` equal to:
|
|||||||
* `<object>` - otherwise, a JSON object containing:
|
* `<object>` - otherwise, a JSON object containing:
|
||||||
* `lamports: <u64>`, number of lamports assigned to this account, as a u64
|
* `lamports: <u64>`, number of lamports assigned to this account, as a u64
|
||||||
* `owner: <string>`, base-58 encoded Pubkey of the program this account has been assigned to
|
* `owner: <string>`, base-58 encoded Pubkey of the program this account has been assigned to
|
||||||
* `data: <string>`, base-58 encoded data associated with the account
|
* `data: <string|object>`, data associated with the account, either as base-58 encoded binary data or JSON format `{<program>: <state>}`, depending on encoding parameter
|
||||||
* `executable: <bool>`, boolean indicating if the account contains a program \(and is strictly read-only\)
|
* `executable: <bool>`, boolean indicating if the account contains a program \(and is strictly read-only\)
|
||||||
* `rentEpoch`: <u64>, the epoch at which this account will next owe rent, as u64
|
* `rentEpoch`: <u64>, the epoch at which this account will next owe rent, as u64
|
||||||
|
|
||||||
@ -156,10 +159,16 @@ The result will be an RpcResponse JSON object with `value` equal to:
|
|||||||
|
|
||||||
```bash
|
```bash
|
||||||
// Request
|
// Request
|
||||||
curl -X POST -H "Content-Type: application/json" -d '{"jsonrpc":"2.0", "id":1, "method":"getAccountInfo", "params":["2gVkYWexTHR5Hb2aLeQN3tnngvWzisFKXDUPrgMHpdST"]}' http://localhost:8899
|
curl -X POST -H "Content-Type: application/json" -d '{"jsonrpc":"2.0", "id":1, "method":"getAccountInfo", "params":["4fYNw3dojWmQ4dXtSGE9epjRGy9pFSx62YypT7avPYvA"]}' http://localhost:8899
|
||||||
|
|
||||||
// Result
|
// Result
|
||||||
{"jsonrpc":"2.0","result":{"context":{"slot":1},"value":{"executable":false,"owner":"4uQeVj5tqViQh7yWWGStvkEG1Zmhx6uasJtWCJziofM","lamports":1,"data":"Joig2k8Ax4JPMpWhXRyc2jMa7Wejz4X1xqVi3i7QRkmVj1ChUgNc4VNpGUQePJGBAui3c6886peU9GEbjsyeANN8JGStprwLbLwcw5wpPjuQQb9mwrjVmoDQBjj3MzZKgeHn6wmnQ5k8DBFuoCYKWWsJfH2gv9FvCzrN6K1CRcQZzF","rentEpoch":2}},"id":1}
|
{"jsonrpc":"2.0","result":{"context":{"slot":1},"value":{"data":"11116bv5nS2h3y12kD1yUKeMZvGcKLSjQgX6BeV7u1FrjeJcKfsHRTPuR3oZ1EioKtYGiYxpxMG5vpbZLsbcBYBEmZZcMKaSoGx9JZeAuWf","executable":false,"lamports":1000000000,"owner":"11111111111111111111111111111111","rentEpoch":2}},"id":1}
|
||||||
|
|
||||||
|
// Request
|
||||||
|
curl -X POST -H "Content-Type: application/json" -d '{"jsonrpc":"2.0", "id":1, "method":"getAccountInfo", "params":["4fYNw3dojWmQ4dXtSGE9epjRGy9pFSx62YypT7avPYvA",{"encoding":"json"}]}' http://localhost:8899
|
||||||
|
|
||||||
|
// Result
|
||||||
|
{"jsonrpc":"2.0","result":{"context":{"slot":1},"value":{"data":{"nonce":{"initialized":{"authority":"Bbqg1M4YVVfbhEzwA9SpC9FhsaG83YMTYoR4a8oTDLX","blockhash":"3xLP3jK6dVJwpeGeTDYTwdDK3TKchUf1gYYGHa4sF3XJ","feeCalculator":{"lamportsPerSignature":5000}}}},"executable":false,"lamports":1000000000,"owner":"11111111111111111111111111111111","rentEpoch":2}},"id":1}
|
||||||
```
|
```
|
||||||
|
|
||||||
### getBalance
|
### getBalance
|
||||||
@ -280,7 +289,8 @@ Returns identity and transaction information about a confirmed block in the ledg
|
|||||||
#### Parameters:
|
#### Parameters:
|
||||||
|
|
||||||
* `<u64>` - slot, as u64 integer
|
* `<u64>` - slot, as u64 integer
|
||||||
* `<string>` - (optional) encoding for each returned Transaction, either "json" or "binary". If not provided, the default encoding is JSON.
|
* `<string>` - (optional) encoding for each returned Transaction, either "json", "jsonParsed", or "binary". If parameter not provided, the default encoding is JSON.
|
||||||
|
Parsed-JSON encoding attempts to use program-specific instruction parsers to return more human-readable and explicit data in the `transaction.message.instructions` list. If parsed-JSON is requested but a parser cannot be found, the instruction falls back to regular JSON encoding (`accounts`, `data`, and `programIdIndex` fields).
|
||||||
|
|
||||||
#### Results:
|
#### Results:
|
||||||
|
|
||||||
@ -399,7 +409,8 @@ Returns transaction details for a confirmed transaction
|
|||||||
#### Parameters:
|
#### Parameters:
|
||||||
|
|
||||||
* `<string>` - transaction signature as base-58 encoded string
|
* `<string>` - transaction signature as base-58 encoded string
|
||||||
* `<string>` - (optional) encoding for the returned Transaction, either "json" or "binary". If not provided, the default encoding is JSON.
|
* `<string>` - (optional) encoding for the returned Transaction, either "json", "jsonParsed", or "binary". If parameter not provided, the default encoding is JSON.
|
||||||
|
Parsed-JSON encoding attempts to use program-specific instruction parsers to return more human-readable and explicit data in the `transaction.message.instructions` list. If parsed-JSON is requested but a parser cannot be found, the instruction falls back to regular JSON encoding (`accounts`, `data`, and `programIdIndex` fields).
|
||||||
|
|
||||||
#### Results:
|
#### Results:
|
||||||
|
|
||||||
@ -778,6 +789,8 @@ Returns all accounts owned by the provided program Pubkey
|
|||||||
* `<string>` - Pubkey of program, as base-58 encoded string
|
* `<string>` - Pubkey of program, as base-58 encoded string
|
||||||
* `<object>` - (optional) Configuration object containing the following optional fields:
|
* `<object>` - (optional) Configuration object containing the following optional fields:
|
||||||
* (optional) [Commitment](jsonrpc-api.md#configuring-state-commitment)
|
* (optional) [Commitment](jsonrpc-api.md#configuring-state-commitment)
|
||||||
|
* (optional) `encoding: <string>` - encoding for Account data, either "binary" or jsonParsed". If parameter not provided, the default encoding is binary.
|
||||||
|
Parsed-JSON encoding attempts to use program-specific state parsers to return more human-readable and explicit account state data. If parsed-JSON is requested but a parser cannot be found, the field falls back to binary encoding, detectable when the `data` field is type `<string>`.
|
||||||
* (optional) `filters: <array>` - filter results using various [filter objects](jsonrpc-api.md#filters); account must meet all filter criteria to be included in results
|
* (optional) `filters: <array>` - filter results using various [filter objects](jsonrpc-api.md#filters); account must meet all filter criteria to be included in results
|
||||||
|
|
||||||
##### Filters:
|
##### Filters:
|
||||||
@ -795,7 +808,7 @@ The result field will be an array of JSON objects, which will contain:
|
|||||||
* `account: <object>` - a JSON object, with the following sub fields:
|
* `account: <object>` - a JSON object, with the following sub fields:
|
||||||
* `lamports: <u64>`, number of lamports assigned to this account, as a u64
|
* `lamports: <u64>`, number of lamports assigned to this account, as a u64
|
||||||
* `owner: <string>`, base-58 encoded Pubkey of the program this account has been assigned to
|
* `owner: <string>`, base-58 encoded Pubkey of the program this account has been assigned to
|
||||||
* `data: <string>`, base-58 encoded data associated with the account
|
`data: <string|object>`, data associated with the account, either as base-58 encoded binary data or JSON format `{<program>: <state>}`, depending on encoding parameter
|
||||||
* `executable: <bool>`, boolean indicating if the account contains a program \(and is strictly read-only\)
|
* `executable: <bool>`, boolean indicating if the account contains a program \(and is strictly read-only\)
|
||||||
* `rentEpoch`: <u64>, the epoch at which this account will next owe rent, as u64
|
* `rentEpoch`: <u64>, the epoch at which this account will next owe rent, as u64
|
||||||
|
|
||||||
|
@ -37,8 +37,8 @@ use solana_sdk::{
|
|||||||
transaction::Transaction,
|
transaction::Transaction,
|
||||||
};
|
};
|
||||||
use solana_transaction_status::{
|
use solana_transaction_status::{
|
||||||
ConfirmedBlock, ConfirmedTransaction, EncodedTransaction, Rewards, RpcTransactionStatusMeta,
|
ConfirmedBlock, ConfirmedTransaction, EncodedTransaction, Rewards, TransactionStatusMeta,
|
||||||
TransactionEncoding, TransactionStatusMeta, TransactionWithStatusMeta,
|
TransactionWithStatusMeta, UiTransactionEncoding, UiTransactionStatusMeta,
|
||||||
};
|
};
|
||||||
use solana_vote_program::{vote_instruction::VoteInstruction, vote_state::TIMESTAMP_SLOT_INTERVAL};
|
use solana_vote_program::{vote_instruction::VoteInstruction, vote_state::TIMESTAMP_SLOT_INTERVAL};
|
||||||
use std::{
|
use std::{
|
||||||
@ -1580,7 +1580,7 @@ impl Blockstore {
|
|||||||
pub fn get_confirmed_block(
|
pub fn get_confirmed_block(
|
||||||
&self,
|
&self,
|
||||||
slot: Slot,
|
slot: Slot,
|
||||||
encoding: Option<TransactionEncoding>,
|
encoding: Option<UiTransactionEncoding>,
|
||||||
) -> Result<ConfirmedBlock> {
|
) -> Result<ConfirmedBlock> {
|
||||||
datapoint_info!(
|
datapoint_info!(
|
||||||
"blockstore-rpc-api",
|
"blockstore-rpc-api",
|
||||||
@ -1592,7 +1592,7 @@ impl Blockstore {
|
|||||||
if *lowest_cleanup_slot > 0 && *lowest_cleanup_slot >= slot {
|
if *lowest_cleanup_slot > 0 && *lowest_cleanup_slot >= slot {
|
||||||
return Err(BlockstoreError::SlotCleanedUp);
|
return Err(BlockstoreError::SlotCleanedUp);
|
||||||
}
|
}
|
||||||
let encoding = encoding.unwrap_or(TransactionEncoding::Json);
|
let encoding = encoding.unwrap_or(UiTransactionEncoding::Json);
|
||||||
if self.is_root(slot) {
|
if self.is_root(slot) {
|
||||||
let slot_meta_cf = self.db.column::<cf::SlotMeta>();
|
let slot_meta_cf = self.db.column::<cf::SlotMeta>();
|
||||||
let slot_meta = match slot_meta_cf.get(slot)? {
|
let slot_meta = match slot_meta_cf.get(slot)? {
|
||||||
@ -1643,7 +1643,7 @@ impl Blockstore {
|
|||||||
fn map_transactions_to_statuses<'a>(
|
fn map_transactions_to_statuses<'a>(
|
||||||
&self,
|
&self,
|
||||||
slot: Slot,
|
slot: Slot,
|
||||||
encoding: TransactionEncoding,
|
encoding: UiTransactionEncoding,
|
||||||
iterator: impl Iterator<Item = Transaction> + 'a,
|
iterator: impl Iterator<Item = Transaction> + 'a,
|
||||||
) -> Vec<TransactionWithStatusMeta> {
|
) -> Vec<TransactionWithStatusMeta> {
|
||||||
iterator
|
iterator
|
||||||
@ -1655,7 +1655,7 @@ impl Blockstore {
|
|||||||
meta: self
|
meta: self
|
||||||
.read_transaction_status((signature, slot))
|
.read_transaction_status((signature, slot))
|
||||||
.expect("Expect database get to succeed")
|
.expect("Expect database get to succeed")
|
||||||
.map(RpcTransactionStatusMeta::from),
|
.map(UiTransactionStatusMeta::from),
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.collect()
|
.collect()
|
||||||
@ -1825,7 +1825,7 @@ impl Blockstore {
|
|||||||
pub fn get_confirmed_transaction(
|
pub fn get_confirmed_transaction(
|
||||||
&self,
|
&self,
|
||||||
signature: Signature,
|
signature: Signature,
|
||||||
encoding: Option<TransactionEncoding>,
|
encoding: Option<UiTransactionEncoding>,
|
||||||
) -> Result<Option<ConfirmedTransaction>> {
|
) -> Result<Option<ConfirmedTransaction>> {
|
||||||
datapoint_info!(
|
datapoint_info!(
|
||||||
"blockstore-rpc-api",
|
"blockstore-rpc-api",
|
||||||
@ -1834,7 +1834,7 @@ impl Blockstore {
|
|||||||
if let Some((slot, status)) = self.get_transaction_status(signature.clone())? {
|
if let Some((slot, status)) = self.get_transaction_status(signature.clone())? {
|
||||||
let transaction = self.find_transaction_in_slot(slot, signature)?
|
let transaction = self.find_transaction_in_slot(slot, signature)?
|
||||||
.expect("Transaction to exist in slot entries if it exists in statuses and hasn't been cleaned up");
|
.expect("Transaction to exist in slot entries if it exists in statuses and hasn't been cleaned up");
|
||||||
let encoding = encoding.unwrap_or(TransactionEncoding::Json);
|
let encoding = encoding.unwrap_or(UiTransactionEncoding::Json);
|
||||||
let encoded_transaction = EncodedTransaction::encode(transaction, encoding);
|
let encoded_transaction = EncodedTransaction::encode(transaction, encoding);
|
||||||
Ok(Some(ConfirmedTransaction {
|
Ok(Some(ConfirmedTransaction {
|
||||||
slot,
|
slot,
|
||||||
@ -5164,7 +5164,7 @@ pub mod tests {
|
|||||||
.put_meta_bytes(slot - 1, &serialize(&parent_meta).unwrap())
|
.put_meta_bytes(slot - 1, &serialize(&parent_meta).unwrap())
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
let expected_transactions: Vec<(Transaction, Option<RpcTransactionStatusMeta>)> = entries
|
let expected_transactions: Vec<(Transaction, Option<UiTransactionStatusMeta>)> = entries
|
||||||
.iter()
|
.iter()
|
||||||
.cloned()
|
.cloned()
|
||||||
.filter(|entry| !entry.is_tick())
|
.filter(|entry| !entry.is_tick())
|
||||||
@ -5228,7 +5228,7 @@ pub mod tests {
|
|||||||
.iter()
|
.iter()
|
||||||
.cloned()
|
.cloned()
|
||||||
.map(|(tx, meta)| TransactionWithStatusMeta {
|
.map(|(tx, meta)| TransactionWithStatusMeta {
|
||||||
transaction: EncodedTransaction::encode(tx, TransactionEncoding::Json),
|
transaction: EncodedTransaction::encode(tx, UiTransactionEncoding::Json),
|
||||||
meta,
|
meta,
|
||||||
})
|
})
|
||||||
.collect(),
|
.collect(),
|
||||||
@ -5249,7 +5249,7 @@ pub mod tests {
|
|||||||
.iter()
|
.iter()
|
||||||
.cloned()
|
.cloned()
|
||||||
.map(|(tx, meta)| TransactionWithStatusMeta {
|
.map(|(tx, meta)| TransactionWithStatusMeta {
|
||||||
transaction: EncodedTransaction::encode(tx, TransactionEncoding::Json),
|
transaction: EncodedTransaction::encode(tx, UiTransactionEncoding::Json),
|
||||||
meta,
|
meta,
|
||||||
})
|
})
|
||||||
.collect(),
|
.collect(),
|
||||||
@ -5866,7 +5866,7 @@ pub mod tests {
|
|||||||
blockstore.insert_shreds(shreds, None, false).unwrap();
|
blockstore.insert_shreds(shreds, None, false).unwrap();
|
||||||
blockstore.set_roots(&[slot - 1, slot]).unwrap();
|
blockstore.set_roots(&[slot - 1, slot]).unwrap();
|
||||||
|
|
||||||
let expected_transactions: Vec<(Transaction, Option<RpcTransactionStatusMeta>)> = entries
|
let expected_transactions: Vec<(Transaction, Option<UiTransactionStatusMeta>)> = entries
|
||||||
.iter()
|
.iter()
|
||||||
.cloned()
|
.cloned()
|
||||||
.filter(|entry| !entry.is_tick())
|
.filter(|entry| !entry.is_tick())
|
||||||
@ -5909,7 +5909,7 @@ pub mod tests {
|
|||||||
for (transaction, status) in expected_transactions.clone() {
|
for (transaction, status) in expected_transactions.clone() {
|
||||||
let signature = transaction.signatures[0];
|
let signature = transaction.signatures[0];
|
||||||
let encoded_transaction =
|
let encoded_transaction =
|
||||||
EncodedTransaction::encode(transaction, TransactionEncoding::Json);
|
EncodedTransaction::encode(transaction, UiTransactionEncoding::Json);
|
||||||
let expected_transaction = ConfirmedTransaction {
|
let expected_transaction = ConfirmedTransaction {
|
||||||
slot,
|
slot,
|
||||||
transaction: TransactionWithStatusMeta {
|
transaction: TransactionWithStatusMeta {
|
||||||
@ -6137,7 +6137,7 @@ pub mod tests {
|
|||||||
|
|
||||||
let map = blockstore.map_transactions_to_statuses(
|
let map = blockstore.map_transactions_to_statuses(
|
||||||
slot,
|
slot,
|
||||||
TransactionEncoding::Json,
|
UiTransactionEncoding::Json,
|
||||||
transactions.into_iter(),
|
transactions.into_iter(),
|
||||||
);
|
);
|
||||||
assert_eq!(map.len(), 5);
|
assert_eq!(map.len(), 5);
|
||||||
|
@ -7,7 +7,7 @@ use solana_sdk::{
|
|||||||
pubkey::Pubkey, signature::Signature, transaction::Transaction,
|
pubkey::Pubkey, signature::Signature, transaction::Transaction,
|
||||||
};
|
};
|
||||||
use solana_stake_program::{stake_instruction::StakeInstruction, stake_state::Lockup};
|
use solana_stake_program::{stake_instruction::StakeInstruction, stake_state::Lockup};
|
||||||
use solana_transaction_status::{ConfirmedBlock, RpcTransactionStatusMeta, TransactionEncoding};
|
use solana_transaction_status::{ConfirmedBlock, UiTransactionEncoding, UiTransactionStatusMeta};
|
||||||
use std::{collections::HashMap, thread::sleep, time::Duration};
|
use std::{collections::HashMap, thread::sleep, time::Duration};
|
||||||
|
|
||||||
pub type PubkeyString = String;
|
pub type PubkeyString = String;
|
||||||
@ -65,7 +65,7 @@ impl AccountsInfo {
|
|||||||
fn process_transaction(
|
fn process_transaction(
|
||||||
slot: Slot,
|
slot: Slot,
|
||||||
transaction: &Transaction,
|
transaction: &Transaction,
|
||||||
meta: &RpcTransactionStatusMeta,
|
meta: &UiTransactionStatusMeta,
|
||||||
accounts: &mut HashMap<PubkeyString, AccountInfo>,
|
accounts: &mut HashMap<PubkeyString, AccountInfo>,
|
||||||
) {
|
) {
|
||||||
let mut last_instruction = true;
|
let mut last_instruction = true;
|
||||||
@ -289,7 +289,7 @@ fn load_blocks(
|
|||||||
let mut blocks = vec![];
|
let mut blocks = vec![];
|
||||||
for slot in slots.into_iter() {
|
for slot in slots.into_iter() {
|
||||||
let block =
|
let block =
|
||||||
rpc_client.get_confirmed_block_with_encoding(slot, TransactionEncoding::Binary)?;
|
rpc_client.get_confirmed_block_with_encoding(slot, UiTransactionEncoding::Binary)?;
|
||||||
blocks.push((slot, block));
|
blocks.push((slot, block));
|
||||||
}
|
}
|
||||||
Ok(blocks)
|
Ok(blocks)
|
||||||
|
@ -11,9 +11,13 @@ edition = "2018"
|
|||||||
[dependencies]
|
[dependencies]
|
||||||
bincode = "1.2.1"
|
bincode = "1.2.1"
|
||||||
bs58 = "0.3.1"
|
bs58 = "0.3.1"
|
||||||
|
Inflector = "0.11.4"
|
||||||
|
lazy_static = "1.4.0"
|
||||||
solana-sdk = { path = "../sdk", version = "1.2.9" }
|
solana-sdk = { path = "../sdk", version = "1.2.9" }
|
||||||
|
spl-memo = "1.0.0"
|
||||||
serde = "1.0.110"
|
serde = "1.0.110"
|
||||||
serde_derive = "1.0.103"
|
serde_derive = "1.0.103"
|
||||||
|
serde_json = "1.0.54"
|
||||||
|
|
||||||
[package.metadata.docs.rs]
|
[package.metadata.docs.rs]
|
||||||
targets = ["x86_64-unknown-linux-gnu"]
|
targets = ["x86_64-unknown-linux-gnu"]
|
||||||
|
@ -1,22 +1,48 @@
|
|||||||
#[macro_use]
|
#[macro_use]
|
||||||
|
extern crate lazy_static;
|
||||||
|
#[macro_use]
|
||||||
extern crate serde_derive;
|
extern crate serde_derive;
|
||||||
|
|
||||||
|
pub mod parse_accounts;
|
||||||
|
pub mod parse_instruction;
|
||||||
|
|
||||||
|
use crate::{parse_accounts::parse_accounts, parse_instruction::parse};
|
||||||
|
use serde_json::Value;
|
||||||
use solana_sdk::{
|
use solana_sdk::{
|
||||||
clock::Slot,
|
clock::Slot,
|
||||||
commitment_config::CommitmentConfig,
|
commitment_config::CommitmentConfig,
|
||||||
|
instruction::CompiledInstruction,
|
||||||
message::MessageHeader,
|
message::MessageHeader,
|
||||||
transaction::{Result, Transaction, TransactionError},
|
transaction::{Result, Transaction, TransactionError},
|
||||||
};
|
};
|
||||||
|
|
||||||
/// A duplicate representation of a Message for pretty JSON serialization
|
/// A duplicate representation of an Instruction for pretty JSON serialization
|
||||||
|
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
|
||||||
|
#[serde(rename_all = "camelCase", untagged)]
|
||||||
|
pub enum UiInstruction {
|
||||||
|
Compiled(UiCompiledInstruction),
|
||||||
|
Parsed(Value),
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A duplicate representation of a CompiledInstruction for pretty JSON serialization
|
||||||
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
|
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
|
||||||
#[serde(rename_all = "camelCase")]
|
#[serde(rename_all = "camelCase")]
|
||||||
pub struct RpcCompiledInstruction {
|
pub struct UiCompiledInstruction {
|
||||||
pub program_id_index: u8,
|
pub program_id_index: u8,
|
||||||
pub accounts: Vec<u8>,
|
pub accounts: Vec<u8>,
|
||||||
pub data: String,
|
pub data: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl From<&CompiledInstruction> for UiCompiledInstruction {
|
||||||
|
fn from(instruction: &CompiledInstruction) -> Self {
|
||||||
|
Self {
|
||||||
|
program_id_index: instruction.program_id_index,
|
||||||
|
accounts: instruction.accounts.clone(),
|
||||||
|
data: bs58::encode(instruction.data.clone()).into_string(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
|
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
|
||||||
#[serde(rename_all = "camelCase")]
|
#[serde(rename_all = "camelCase")]
|
||||||
pub struct TransactionStatusMeta {
|
pub struct TransactionStatusMeta {
|
||||||
@ -37,9 +63,10 @@ impl Default for TransactionStatusMeta {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// A duplicate representation of TransactionStatusMeta with `err` field
|
||||||
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
|
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
|
||||||
#[serde(rename_all = "camelCase")]
|
#[serde(rename_all = "camelCase")]
|
||||||
pub struct RpcTransactionStatusMeta {
|
pub struct UiTransactionStatusMeta {
|
||||||
pub err: Option<TransactionError>,
|
pub err: Option<TransactionError>,
|
||||||
pub status: Result<()>, // This field is deprecated. See https://github.com/solana-labs/solana/issues/9302
|
pub status: Result<()>, // This field is deprecated. See https://github.com/solana-labs/solana/issues/9302
|
||||||
pub fee: u64,
|
pub fee: u64,
|
||||||
@ -47,7 +74,7 @@ pub struct RpcTransactionStatusMeta {
|
|||||||
pub post_balances: Vec<u64>,
|
pub post_balances: Vec<u64>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<TransactionStatusMeta> for RpcTransactionStatusMeta {
|
impl From<TransactionStatusMeta> for UiTransactionStatusMeta {
|
||||||
fn from(meta: TransactionStatusMeta) -> Self {
|
fn from(meta: TransactionStatusMeta) -> Self {
|
||||||
Self {
|
Self {
|
||||||
err: meta.status.clone().err(),
|
err: meta.status.clone().err(),
|
||||||
@ -104,76 +131,112 @@ pub struct ConfirmedTransaction {
|
|||||||
/// A duplicate representation of a Transaction for pretty JSON serialization
|
/// A duplicate representation of a Transaction for pretty JSON serialization
|
||||||
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
|
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
|
||||||
#[serde(rename_all = "camelCase")]
|
#[serde(rename_all = "camelCase")]
|
||||||
pub struct RpcTransaction {
|
pub struct UiTransaction {
|
||||||
pub signatures: Vec<String>,
|
pub signatures: Vec<String>,
|
||||||
pub message: RpcMessage,
|
pub message: UiMessage,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A duplicate representation of a Message for pretty JSON serialization
|
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
|
||||||
|
#[serde(rename_all = "camelCase", untagged)]
|
||||||
|
pub enum UiMessage {
|
||||||
|
Parsed(UiParsedMessage),
|
||||||
|
Raw(UiRawMessage),
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A duplicate representation of a Message, in raw format, for pretty JSON serialization
|
||||||
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
|
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
|
||||||
#[serde(rename_all = "camelCase")]
|
#[serde(rename_all = "camelCase")]
|
||||||
pub struct RpcMessage {
|
pub struct UiRawMessage {
|
||||||
pub header: MessageHeader,
|
pub header: MessageHeader,
|
||||||
pub account_keys: Vec<String>,
|
pub account_keys: Vec<String>,
|
||||||
pub recent_blockhash: String,
|
pub recent_blockhash: String,
|
||||||
pub instructions: Vec<RpcCompiledInstruction>,
|
pub instructions: Vec<UiCompiledInstruction>,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A duplicate representation of a Message, in parsed format, for pretty JSON serialization
|
||||||
|
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
|
||||||
|
#[serde(rename_all = "camelCase")]
|
||||||
|
pub struct UiParsedMessage {
|
||||||
|
pub account_keys: Value,
|
||||||
|
pub recent_blockhash: String,
|
||||||
|
pub instructions: Vec<UiInstruction>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, PartialEq, Serialize, Deserialize)]
|
#[derive(Debug, PartialEq, Serialize, Deserialize)]
|
||||||
#[serde(rename_all = "camelCase")]
|
#[serde(rename_all = "camelCase")]
|
||||||
pub struct TransactionWithStatusMeta {
|
pub struct TransactionWithStatusMeta {
|
||||||
pub transaction: EncodedTransaction,
|
pub transaction: EncodedTransaction,
|
||||||
pub meta: Option<RpcTransactionStatusMeta>,
|
pub meta: Option<UiTransactionStatusMeta>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq)]
|
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq)]
|
||||||
#[serde(rename_all = "camelCase")]
|
#[serde(rename_all = "camelCase")]
|
||||||
pub enum TransactionEncoding {
|
pub enum UiTransactionEncoding {
|
||||||
Binary,
|
Binary,
|
||||||
Json,
|
Json,
|
||||||
|
JsonParsed,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
|
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
|
||||||
#[serde(rename_all = "camelCase", untagged)]
|
#[serde(rename_all = "camelCase", untagged)]
|
||||||
pub enum EncodedTransaction {
|
pub enum EncodedTransaction {
|
||||||
Binary(String),
|
Binary(String),
|
||||||
Json(RpcTransaction),
|
Json(UiTransaction),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl EncodedTransaction {
|
impl EncodedTransaction {
|
||||||
pub fn encode(transaction: Transaction, encoding: TransactionEncoding) -> Self {
|
pub fn encode(transaction: Transaction, encoding: UiTransactionEncoding) -> Self {
|
||||||
if encoding == TransactionEncoding::Json {
|
match encoding {
|
||||||
EncodedTransaction::Json(RpcTransaction {
|
UiTransactionEncoding::Binary => EncodedTransaction::Binary(
|
||||||
signatures: transaction
|
|
||||||
.signatures
|
|
||||||
.iter()
|
|
||||||
.map(|sig| sig.to_string())
|
|
||||||
.collect(),
|
|
||||||
message: RpcMessage {
|
|
||||||
header: transaction.message.header,
|
|
||||||
account_keys: transaction
|
|
||||||
.message
|
|
||||||
.account_keys
|
|
||||||
.iter()
|
|
||||||
.map(|pubkey| pubkey.to_string())
|
|
||||||
.collect(),
|
|
||||||
recent_blockhash: transaction.message.recent_blockhash.to_string(),
|
|
||||||
instructions: transaction
|
|
||||||
.message
|
|
||||||
.instructions
|
|
||||||
.iter()
|
|
||||||
.map(|instruction| RpcCompiledInstruction {
|
|
||||||
program_id_index: instruction.program_id_index,
|
|
||||||
accounts: instruction.accounts.clone(),
|
|
||||||
data: bs58::encode(instruction.data.clone()).into_string(),
|
|
||||||
})
|
|
||||||
.collect(),
|
|
||||||
},
|
|
||||||
})
|
|
||||||
} else {
|
|
||||||
EncodedTransaction::Binary(
|
|
||||||
bs58::encode(bincode::serialize(&transaction).unwrap()).into_string(),
|
bs58::encode(bincode::serialize(&transaction).unwrap()).into_string(),
|
||||||
)
|
),
|
||||||
|
_ => {
|
||||||
|
let message = if encoding == UiTransactionEncoding::Json {
|
||||||
|
UiMessage::Raw(UiRawMessage {
|
||||||
|
header: transaction.message.header,
|
||||||
|
account_keys: transaction
|
||||||
|
.message
|
||||||
|
.account_keys
|
||||||
|
.iter()
|
||||||
|
.map(|pubkey| pubkey.to_string())
|
||||||
|
.collect(),
|
||||||
|
recent_blockhash: transaction.message.recent_blockhash.to_string(),
|
||||||
|
instructions: transaction
|
||||||
|
.message
|
||||||
|
.instructions
|
||||||
|
.iter()
|
||||||
|
.map(|instruction| instruction.into())
|
||||||
|
.collect(),
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
UiMessage::Parsed(UiParsedMessage {
|
||||||
|
account_keys: parse_accounts(&transaction.message),
|
||||||
|
recent_blockhash: transaction.message.recent_blockhash.to_string(),
|
||||||
|
instructions: transaction
|
||||||
|
.message
|
||||||
|
.instructions
|
||||||
|
.iter()
|
||||||
|
.map(|instruction| {
|
||||||
|
let program_id =
|
||||||
|
instruction.program_id(&transaction.message.account_keys);
|
||||||
|
if let Some(parsed_instruction) = parse(program_id, instruction) {
|
||||||
|
UiInstruction::Parsed(parsed_instruction)
|
||||||
|
} else {
|
||||||
|
UiInstruction::Compiled(instruction.into())
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.collect(),
|
||||||
|
})
|
||||||
|
};
|
||||||
|
EncodedTransaction::Json(UiTransaction {
|
||||||
|
signatures: transaction
|
||||||
|
.signatures
|
||||||
|
.iter()
|
||||||
|
.map(|sig| sig.to_string())
|
||||||
|
.collect(),
|
||||||
|
message,
|
||||||
|
})
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
pub fn decode(&self) -> Option<Transaction> {
|
pub fn decode(&self) -> Option<Transaction> {
|
||||||
|
56
transaction-status/src/parse_accounts.rs
Normal file
56
transaction-status/src/parse_accounts.rs
Normal file
@ -0,0 +1,56 @@
|
|||||||
|
use serde_json::{json, Value};
|
||||||
|
use solana_sdk::message::Message;
|
||||||
|
|
||||||
|
type AccountAttributes = Vec<AccountAttribute>;
|
||||||
|
|
||||||
|
#[derive(Serialize, Deserialize)]
|
||||||
|
#[serde(rename_all = "camelCase")]
|
||||||
|
enum AccountAttribute {
|
||||||
|
Signer,
|
||||||
|
Writable,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn parse_accounts(message: &Message) -> Value {
|
||||||
|
let mut accounts: Vec<Value> = vec![];
|
||||||
|
for (i, account_key) in message.account_keys.iter().enumerate() {
|
||||||
|
let mut attributes: AccountAttributes = vec![];
|
||||||
|
if message.is_writable(i) {
|
||||||
|
attributes.push(AccountAttribute::Writable);
|
||||||
|
}
|
||||||
|
if message.is_signer(i) {
|
||||||
|
attributes.push(AccountAttribute::Signer);
|
||||||
|
}
|
||||||
|
accounts.push(json!({ account_key.to_string(): attributes }));
|
||||||
|
}
|
||||||
|
json!(accounts)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod test {
|
||||||
|
use super::*;
|
||||||
|
use solana_sdk::{message::MessageHeader, pubkey::Pubkey};
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_parse_accounts() {
|
||||||
|
let pubkey0 = Pubkey::new_rand();
|
||||||
|
let pubkey1 = Pubkey::new_rand();
|
||||||
|
let pubkey2 = Pubkey::new_rand();
|
||||||
|
let pubkey3 = Pubkey::new_rand();
|
||||||
|
let mut message = Message::default();
|
||||||
|
message.header = MessageHeader {
|
||||||
|
num_required_signatures: 2,
|
||||||
|
num_readonly_signed_accounts: 1,
|
||||||
|
num_readonly_unsigned_accounts: 1,
|
||||||
|
};
|
||||||
|
message.account_keys = vec![pubkey0, pubkey1, pubkey2, pubkey3];
|
||||||
|
|
||||||
|
let expected_json = json!([
|
||||||
|
{pubkey0.to_string(): ["writable", "signer"]},
|
||||||
|
{pubkey1.to_string(): ["signer"]},
|
||||||
|
{pubkey2.to_string(): ["writable"]},
|
||||||
|
{pubkey3.to_string(): []},
|
||||||
|
]);
|
||||||
|
|
||||||
|
assert_eq!(parse_accounts(&message), expected_json);
|
||||||
|
}
|
||||||
|
}
|
59
transaction-status/src/parse_instruction.rs
Normal file
59
transaction-status/src/parse_instruction.rs
Normal file
@ -0,0 +1,59 @@
|
|||||||
|
use inflector::Inflector;
|
||||||
|
use serde_json::{json, Value};
|
||||||
|
use solana_sdk::{instruction::CompiledInstruction, pubkey::Pubkey};
|
||||||
|
use std::{
|
||||||
|
collections::HashMap,
|
||||||
|
str::{from_utf8, FromStr},
|
||||||
|
};
|
||||||
|
|
||||||
|
lazy_static! {
|
||||||
|
static ref MEMO_PROGRAM_ID: Pubkey = Pubkey::from_str(&spl_memo::id().to_string()).unwrap();
|
||||||
|
static ref PARSABLE_PROGRAM_IDS: HashMap<Pubkey, ParsableProgram> = {
|
||||||
|
let mut m = HashMap::new();
|
||||||
|
m.insert(*MEMO_PROGRAM_ID, ParsableProgram::SplMemo);
|
||||||
|
m
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Serialize, Deserialize)]
|
||||||
|
#[serde(rename_all = "camelCase")]
|
||||||
|
enum ParsableProgram {
|
||||||
|
SplMemo,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn parse(program_id: &Pubkey, instruction: &CompiledInstruction) -> Option<Value> {
|
||||||
|
PARSABLE_PROGRAM_IDS.get(program_id).map(|program_name| {
|
||||||
|
let parsed_json = match program_name {
|
||||||
|
ParsableProgram::SplMemo => parse_memo(instruction),
|
||||||
|
};
|
||||||
|
json!({ format!("{:?}", program_name).to_kebab_case(): parsed_json })
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
fn parse_memo(instruction: &CompiledInstruction) -> Value {
|
||||||
|
Value::String(from_utf8(&instruction.data).unwrap().to_string())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod test {
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_parse() {
|
||||||
|
let memo_instruction = CompiledInstruction {
|
||||||
|
program_id_index: 0,
|
||||||
|
accounts: vec![],
|
||||||
|
data: vec![240, 159, 166, 150],
|
||||||
|
};
|
||||||
|
let expected_json = json!({
|
||||||
|
"spl-memo": "🦖"
|
||||||
|
});
|
||||||
|
assert_eq!(
|
||||||
|
parse(&MEMO_PROGRAM_ID, &memo_instruction),
|
||||||
|
Some(expected_json)
|
||||||
|
);
|
||||||
|
|
||||||
|
let non_parsable_program_id = Pubkey::new(&[1; 32]);
|
||||||
|
assert_eq!(parse(&non_parsable_program_id, &memo_instruction), None);
|
||||||
|
}
|
||||||
|
}
|
@ -15,7 +15,7 @@ use solana_sdk::{
|
|||||||
clock::Slot, hash::Hash, native_token::lamports_to_sol, program_utils::limited_deserialize,
|
clock::Slot, hash::Hash, native_token::lamports_to_sol, program_utils::limited_deserialize,
|
||||||
pubkey::Pubkey,
|
pubkey::Pubkey,
|
||||||
};
|
};
|
||||||
use solana_transaction_status::{ConfirmedBlock, TransactionEncoding};
|
use solana_transaction_status::{ConfirmedBlock, UiTransactionEncoding};
|
||||||
use solana_vote_program::vote_instruction::VoteInstruction;
|
use solana_vote_program::vote_instruction::VoteInstruction;
|
||||||
use std::{
|
use std::{
|
||||||
error,
|
error,
|
||||||
@ -229,7 +229,7 @@ fn load_blocks(
|
|||||||
let mut blocks = vec![];
|
let mut blocks = vec![];
|
||||||
for slot in slots.into_iter() {
|
for slot in slots.into_iter() {
|
||||||
let block =
|
let block =
|
||||||
rpc_client.get_confirmed_block_with_encoding(slot, TransactionEncoding::Binary)?;
|
rpc_client.get_confirmed_block_with_encoding(slot, UiTransactionEncoding::Binary)?;
|
||||||
blocks.push((slot, block));
|
blocks.push((slot, block));
|
||||||
}
|
}
|
||||||
Ok(blocks)
|
Ok(blocks)
|
||||||
|
Reference in New Issue
Block a user