Skip to main content

Retrieve a contract code ledger entry using the Python SDK

When you deploy a contract, first the code is "installed" (i.e., it is uploaded onto the blockchain). This creates a LedgerEntry containing the Wasm byte-code, which is uniquely identified by its hash (that is, the hash of the uploaded code itself). Then, when the contract is "deployed," we create a LedgerEntry with a reference to that code's hash. So fetching the contract code is a two-step process:

  1. First, we look up the contract itself, to see which code hash it is referencing.
  2. Then, we can look up the raw Wasm byte-code using that hash.
from stellar_sdk import xdr
from stellar_sdk.strkey import StrKey

def get_ledger_key_contract_code(contract_id: str) -> str:
ledger_key = xdr.LedgerKey(
type=xdr.LedgerEntryType.CONTRACT_DATA,
contract_data=xdr.LedgerKeyContractData(
contract_id=xdr.Hash(StrKey.decodeContract(contract_id)),
key=xdr.SCVal(
type=xdr.SCValType.SCV_LEDGER_KEY_CONTRACT_EXECUTABLE,
),
),
)
return ledger_key.to_xdr()

print(
get_ledger_key_contract_code(
"CA3D5KRYM6CB7OWQ6TWYRR3Z4T7GNZLKERYNZGGA5SOAOPIFY6YQGAXE"
)
)
# OUTPUT: AAAABq+aJSfjs7VXHWOwJGujK30xpTI3Zt98YN/As+O6b98jAAAAFA==

We then take our output from this function, and use it as the element in the keys array parameter in our call to the getLedgerEntries method.

{
"jsonrpc": "2.0",
"id": 8675309,
"method": "getLedgerEntries",
"params": {
"keys": ["AAAABq+aJSfjs7VXHWOwJGujK30xpTI3Zt98YN/As+O6b98jAAAAFA=="]
}
}

And the response we get contains the LedgerEntryData that can be used to find the hash we must use to request the Wasm byte-code. This hash is the LedgerKey that's been associated with the deployed contract code.

{
"jsonrpc": "2.0",
"id": 8675309,
"result": {
"entries": [
{
"key": "AAAABq+aJSfjs7VXHWOwJGujK30xpTI3Zt98YN/As+O6b98jAAAAFA==",
"xdr": "AAAABq+aJSfjs7VXHWOwJGujK30xpTI3Zt98YN/As+O6b98jAAAAFAAAABIAAAAAZBYoEJT3IaPMMk3FoRmnEQHoDxewPZL+Uor+xWI4uII=",
"lastModifiedLedgerSeq": 261603
}
],
"latestLedger": 262322
}
}

Now take the xdr field from the previous response's result object, and create a LedgerKey from the hash contained inside.

from stellar_sdk import xdr

def get_ledger_key_wasm_id(contract_code_ledger_entry_data: str) -> str:
# First, we dig the wasm_id hash out of the xdr we received from RPC
contract_code_wasm_hash = xdr.LedgerEntryData.from_xdr(
contract_code_ledger_entry_data
).contract_data.val.exec.wasm_id.hash
# Now, we can create the `LedgerKey` as we've done in previous examples
ledger_key = xdr.LedgerKey(
type=xdr.LedgerEntryType.CONTRACT_CODE,
contract_code=xdr.LedgerKeyContractCode(
hash=xdr.hash.Hash(contract_code_wasm_hash)
),
)
return ledger_key.to_xdr()

print(
get_ledger_key_wasm_id(
"AAAABq+aJSfjs7VXHWOwJGujK30xpTI3Zt98YN/As+O6b98jAAAAFAAAABIAAAAAZBYoEJT3IaPMMk3FoRmnEQHoDxewPZL+Uor+xWI4uII="
)
)
# OUTPUT: AAAAB2QWKBCU9yGjzDJNxaEZpxEB6A8XsD2S/lKK/sViOLiC

Now, finally we have a LedgerKey that correspond to the Wasm byte-code that has been deployed under the ContractId we started out with so very long ago. This LedgerKey can be used in a final request to the Soroban-RPC endpoint.

{
"jsonrpc": "2.0",
"id": 8675309,
"method": "getLedgerEntries",
"params": {
"keys": ["AAAAB2QWKBCU9yGjzDJNxaEZpxEB6A8XsD2S/lKK/sViOLiC"]
}
}

And the response we get contains (even more) LedgerEntryData that we can decode and parse to get the actual, deployed, real-life contract byte-code. We'll leave that exercise up to you. You can check out what is contained using the "View XDR" page of the Stellar Laboratory.

{
"jsonrpc": "2.0",
"id": 8675309,
"result": {
"entries": [
{
"key": "AAAAB2QWKBCU9yGjzDJNxaEZpxEB6A8XsD2S/lKK/sViOLiC",
"xdr": "AAAABwAAAABkFigQlPcho8wyTcWhGacRAegPF7A9kv5Siv7FYji4ggAAAlQAYXNtAQAAAAEPA2ACfn4BfmABfgF+YAAAAgcBAXYBRwAAAwQDAQICBQMBABEGGQN/AUGAgMAAC38AQYWAwAALfwBBkIDAAAsHMQUGbWVtb3J5AgAFaGVsbG8AAQFfAAMKX19kYXRhX2VuZAMBC19faGVhcF9iYXNlAwIK4QID1gIDAn8CfgF/I4CAgIAAQSBrIgEkgICAgAACQAJAIACnQf8BcSICQQ5GDQAgAkHKAEcNAQtCACEDQXshAgNAAkACQAJAAkAgAkUNAEIBIQQgAkGFgMCAAGotAAAiBUHfAEYNAyAFrSEEIAVBUGpBCkkNAiAFQb9/akEaSQ0BAkAgBUGff2pBGk8NACAEQkV8IQQMBAsQgoCAgAAACyABIAA3AwggASADQgiGQg6ENwMAQQAhAgNAAkAgAkEQRw0AQQAhAgJAA0AgAkEQRg0BIAFBEGogAmogASACaikDADcDACACQQhqIQIMAAsLIAFBEGqtQiCGQgSEQoSAgIAgEICAgIAAIQQgAUEgaiSAgICAACAEDwsgAUEQaiACakICNwMAIAJBCGohAgwACwsgBEJLfCEEDAELIARCUnwhBAsgAkEBaiECIAQgA0IGhoQhAwwACwsAAAsEAAAACwIACwsOAQBBgIDAAAsFSGVsbG8AHhFjb250cmFjdGVudm1ldGF2MAAAAAAAAAAUAAAAJQBDDmNvbnRyYWN0c3BlY3YwAAAAAAAAAAAAAAAFaGVsbG8AAAAAAAABAAAAAAAAAAJ0bwAAAAAAEQAAAAEAAAPqAAAAEQ==",
"lastModifiedLedgerSeq": 75206,
"liveUntilLedgerSeq": 320384
}
],
"latestLedger": 262384
}
}