Skip to content

Commit

Permalink
fix: update CLI and tests for new getLedgerEntries (#1021)
Browse files Browse the repository at this point in the history
* fix: add latest_modified_ledger to FullLedgerEntry

Also simplifies parsing FullLedgerEntry

* fix: CLI test for contract read

* fix: update tests to use getLedgerEntries

* fix: nit
  • Loading branch information
willemneal authored Oct 12, 2023
1 parent babcb57 commit b4838f8
Show file tree
Hide file tree
Showing 6 changed files with 74 additions and 69 deletions.
4 changes: 2 additions & 2 deletions cmd/crates/soroban-test/tests/it/hello_world.rs
Original file line number Diff line number Diff line change
Expand Up @@ -310,7 +310,7 @@ fn contract_data_read() {
.arg("--durability=persistent")
.assert()
.success()
.stdout("COUNTER,1,4096\n");
.stdout("COUNTER,1,4,4096\n");

sandbox
.new_assert_cmd("contract")
Expand All @@ -331,7 +331,7 @@ fn contract_data_read() {
.arg("--durability=persistent")
.assert()
.success()
.stdout("COUNTER,2,4096\n");
.stdout("COUNTER,2,4,4096\n");
}

#[test]
Expand Down
2 changes: 1 addition & 1 deletion cmd/soroban-cli/src/commands/contract/bump.rs
Original file line number Diff line number Diff line change
Expand Up @@ -175,7 +175,7 @@ impl Cmd {

if operations[0].changes.is_empty() {
let entry = client.get_full_ledger_entries(&keys).await?;
let expire = entry.entries[0].expiration.expiration_ledger_seq;
let expire = entry.entries[0].expiration_ledger_seq;
if entry.latest_ledger + i64::from(ledgers_to_expire) < i64::from(expire) {
return Ok(expire);
}
Expand Down
33 changes: 18 additions & 15 deletions cmd/soroban-cli/src/commands/contract/read.rs
Original file line number Diff line number Diff line change
@@ -1,15 +1,13 @@
use std::{
convert::Into,
fmt::Debug,
io::{self, stdout},
};

use clap::{command, Parser, ValueEnum};
use sha2::{Digest, Sha256};
use soroban_env_host::{
xdr::{
ContractDataEntry, Error as XdrError, ExpirationEntry, Hash, LedgerEntryData, LedgerKey,
LedgerKeyContractData, ScVal, WriteXdr,
ContractDataEntry, Error as XdrError, LedgerEntryData, LedgerKey, LedgerKeyContractData,
ScVal, WriteXdr,
},
HostError,
};
Expand Down Expand Up @@ -113,18 +111,16 @@ impl Cmd {
fn run_in_sandbox(&self) -> Result<FullLedgerEntries, Error> {
let state = self.config.get_state()?;
let ledger_entries = &state.ledger_entries;

let latest_ledger = u32::try_from(state.ledger_entries.len()).unwrap();
let keys = self.key.parse_keys()?;
let entries = ledger_entries
.iter()
.map(|(k, v)| (k.as_ref().clone(), (v.0.as_ref().clone(), v.1)))
.filter(|(k, _v)| keys.contains(k))
.map(|(key, (v, expiration))| {
Ok(FullLedgerEntry {
expiration: ExpirationEntry {
key_hash: Hash(Sha256::digest(key.to_xdr()?).into()),
expiration_ledger_seq: expiration.unwrap_or_default(),
},
expiration_ledger_seq: expiration.unwrap_or_default(),
last_modified_ledger: latest_ledger,
key,
val: v.data,
})
Expand All @@ -145,7 +141,8 @@ impl Cmd {
for FullLedgerEntry {
key,
val,
expiration,
expiration_ledger_seq,
last_modified_ledger,
} in &entries.entries
{
let (
Expand All @@ -155,8 +152,6 @@ impl Cmd {
else {
return Err(Error::OnlyDataAllowed);
};
let expiration = expiration.expiration_ledger_seq;

let output = match self.output {
Output::String => [
soroban_spec_tools::to_string(key).map_err(|e| Error::CannotPrintResult {
Expand All @@ -167,7 +162,8 @@ impl Cmd {
result: val.clone(),
error: e,
})?,
expiration.to_string(),
last_modified_ledger.to_string(),
expiration_ledger_seq.to_string(),
],
Output::Json => [
serde_json::to_string_pretty(&key).map_err(|error| {
Expand All @@ -182,7 +178,13 @@ impl Cmd {
error,
}
})?,
serde_json::to_string_pretty(&expiration).map_err(|error| {
serde_json::to_string_pretty(&last_modified_ledger).map_err(|error| {
Error::CannotPrintJsonResult {
result: val.clone(),
error,
}
})?,
serde_json::to_string_pretty(&expiration_ledger_seq).map_err(|error| {
Error::CannotPrintJsonResult {
result: val.clone(),
error,
Expand All @@ -192,7 +194,8 @@ impl Cmd {
Output::Xdr => [
key.to_xdr_base64()?,
val.to_xdr_base64()?,
expiration.to_xdr_base64()?,
last_modified_ledger.to_xdr_base64()?,
expiration_ledger_seq.to_xdr_base64()?,
],
};
out.write_record(output)
Expand Down
82 changes: 41 additions & 41 deletions cmd/soroban-cli/src/rpc/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,16 @@ use itertools::Itertools;
use jsonrpsee_core::params::ObjectParams;
use jsonrpsee_core::{self, client::ClientT, rpc_params};
use jsonrpsee_http_client::{HeaderMap, HttpClient, HttpClientBuilder};
use serde_aux::prelude::{deserialize_default_from_null, deserialize_number_from_string};
use sha2::{Digest, Sha256};
use serde_aux::prelude::{
deserialize_default_from_null, deserialize_number_from_string,
deserialize_option_number_from_string,
};
use soroban_env_host::xdr::{
self, AccountEntry, AccountId, ContractDataEntry, DiagnosticEvent, Error as XdrError,
ExpirationEntry, LedgerEntryData, LedgerFootprint, LedgerKey, LedgerKeyAccount,
LedgerKeyExpiration, PublicKey, ReadXdr, SequenceNumber, SorobanAuthorizationEntry,
SorobanResources, Transaction, TransactionEnvelope, TransactionMeta, TransactionMetaV3,
TransactionResult, TransactionV1Envelope, Uint256, VecM, WriteXdr,
LedgerEntryData, LedgerFootprint, LedgerKey, LedgerKeyAccount, PublicKey, ReadXdr,
SequenceNumber, SorobanAuthorizationEntry, SorobanResources, Transaction, TransactionEnvelope,
TransactionMeta, TransactionMetaV3, TransactionResult, TransactionV1Envelope, Uint256, VecM,
WriteXdr,
};
use soroban_env_host::xdr::{DepthLimitedRead, SorobanAuthorizedFunction};
use soroban_sdk::token;
Expand Down Expand Up @@ -96,8 +98,8 @@ pub enum Error {
SpecBase64(#[from] soroban_spec::read::ParseSpecBase64Error),
#[error("Fee was too large {0}")]
LargeFee(u64),
#[error("Failed to parse LedgerEntryData")]
FailedParseLedgerEntryData,
#[error("Failed to parse LedgerEntryData\nkey:{0:?}\nvalue:{1:?}\nexpiration:{2:?}")]
FailedParseLedgerEntryData(LedgerKey, LedgerEntryData, LedgerEntryData),
}

#[derive(serde::Deserialize, serde::Serialize, Debug)]
Expand Down Expand Up @@ -146,14 +148,18 @@ pub struct GetTransactionResponse {
pub struct LedgerEntryResult {
pub key: String,
pub xdr: String,
#[serde(rename = "lastModifiedLedgerSeq")]
pub last_modified_ledger: String,
#[serde(
rename = "lastModifiedLedgerSeq",
deserialize_with = "deserialize_number_from_string"
)]
pub last_modified_ledger: u32,
#[serde(
rename = "expirationLedgerSeq",
skip_serializing_if = "Option::is_none",
deserialize_with = "deserialize_option_number_from_string",
default
)]
pub expiration_ledger_seq: Option<String>,
pub expiration_ledger_seq: Option<u32>,
}

#[derive(serde::Deserialize, serde::Serialize, Debug)]
Expand Down Expand Up @@ -433,7 +439,8 @@ pub enum EventStart {
pub struct FullLedgerEntry {
pub key: LedgerKey,
pub val: LedgerEntryData,
pub expiration: ExpirationEntry,
pub last_modified_ledger: u32,
pub expiration_ledger_seq: u32,
}

#[derive(Debug)]
Expand Down Expand Up @@ -501,10 +508,10 @@ impl Client {

pub async fn verify_network_passphrase(&self, expected: Option<&str>) -> Result<String, Error> {
let server = self.get_network().await?.passphrase;
if expected != Some(&server) {
if let Some(expected_val) = expected {
if let Some(expected) = expected {
if expected != server {
return Err(Error::InvalidNetworkPassphrase {
expected: expected_val.to_string(),
expected: expected.to_string(),
server,
});
}
Expand Down Expand Up @@ -775,35 +782,35 @@ soroban config identity fund {address} --helper-url <url>"#
) -> Result<FullLedgerEntries, Error> {
let keys = ledger_keys
.iter()
.map(|key| Ok(into_keys(key.clone())?.into_iter()))
.flatten_ok()
.collect::<Result<Vec<_>, Error>>()?;
tracing::trace!("{keys:#?}");
.filter(|key| !matches!(key, LedgerKey::Expiration(_)))
.map(Clone::clone)
.collect::<Vec<_>>();
tracing::trace!("keys: {keys:#?}");
let GetLedgerEntriesResponse {
entries,
latest_ledger,
} = self.get_ledger_entries(&keys).await?;
tracing::trace!(?entries);
tracing::trace!("raw: {entries:#?}");
let entries = entries
.as_deref()
.unwrap_or_default()
.iter()
.tuple_windows()
.map(|(key_res, entry_res)| {
let expiration = LedgerEntryData::from_xdr_base64(&entry_res.xdr)?;
if let LedgerEntryData::Expiration(expiration) = expiration {
let key = LedgerKey::from_xdr_base64(&key_res.key)?;
let val = LedgerEntryData::from_xdr_base64(&key_res.xdr)?;
.map(
|LedgerEntryResult {
key,
xdr,
last_modified_ledger,
expiration_ledger_seq,
}| {
Ok(FullLedgerEntry {
key,
val,
expiration,
key: LedgerKey::from_xdr_base64(key)?,
val: LedgerEntryData::from_xdr_base64(xdr)?,
expiration_ledger_seq: expiration_ledger_seq.unwrap_or_default(),
last_modified_ledger: *last_modified_ledger,
})
} else {
Err(Error::FailedParseLedgerEntryData)
}
})
},
)
.collect::<Result<Vec<_>, Error>>()?;
tracing::trace!("parsed: {entries:#?}");
Ok(FullLedgerEntries {
entries,
latest_ledger,
Expand Down Expand Up @@ -960,13 +967,6 @@ pub fn parse_cursor(c: &str) -> Result<(u64, i32), Error> {
Ok((toid_part, start_index))
}

fn into_keys(key: LedgerKey) -> Result<[LedgerKey; 2], Error> {
let expiration = LedgerKey::Expiration(LedgerKeyExpiration {
key_hash: xdr::Hash(Sha256::digest(key.to_xdr()?).into()),
});
Ok([key, expiration])
}

#[cfg(test)]
mod tests {
use super::*;
Expand Down
2 changes: 1 addition & 1 deletion cmd/soroban-rpc/internal/test/cli_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -229,7 +229,7 @@ func getExpirationKey(t *testing.T, key xdr.LedgerKey) xdr.LedgerKey {
}

func getExpirationKeyForCounterLedgerEntry(t *testing.T, strkeyContractID string) xdr.LedgerKey {
return getExpirationKey(t, getCounterLedgerKey(parseContractStrKey(t, strkeyContractID)))
return getCounterLedgerKey(parseContractStrKey(t, strkeyContractID))
}

func parseContractStrKey(t *testing.T, strkeyContractID string) [32]byte {
Expand Down
20 changes: 11 additions & 9 deletions cmd/soroban-rpc/internal/test/simulate_transaction_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -907,25 +907,27 @@ func getExpirationForLedgerEntry(t *testing.T, client *jrpc2.Client, expirationL
func waitForLedgerEntryToExpire(t *testing.T, client *jrpc2.Client, ledgerKey xdr.LedgerKey) {
keyB64, err := xdr.MarshalBase64(ledgerKey)
require.NoError(t, err)
getLedgerEntryrequest := methods.GetLedgerEntryRequest{
Key: keyB64,
request := methods.GetLedgerEntriesRequest{
Keys: []string{keyB64},
}
expired := false
for i := 0; i < 50; i++ {
var getLedgerEntryResult methods.GetLedgerEntryResponse
var result methods.GetLedgerEntriesResponse
var entry xdr.LedgerEntryData
err := client.CallResult(context.Background(), "getLedgerEntry", getLedgerEntryrequest, &getLedgerEntryResult)
err := client.CallResult(context.Background(), "getLedgerEntries", request, &result)
assert.NoError(t, err)
assert.NoError(t, xdr.SafeUnmarshalBase64(getLedgerEntryResult.XDR, &entry))
assert.Equal(t, xdr.LedgerEntryTypeExpiration, entry.Type)
assert.NotEmpty(t, result.Entries)
assert.NoError(t, xdr.SafeUnmarshalBase64(result.Entries[0].XDR, &entry))
assert.NotEqual(t, xdr.LedgerEntryTypeExpiration, entry.Type)
expirationLedgerSeq := xdr.Uint32(*result.Entries[0].ExpirationLedger)
// See https://soroban.stellar.org/docs/fundamentals-and-concepts/state-expiration#expiration-ledger
currentLedger := getLedgerEntryResult.LatestLedger + 1
if xdr.Uint32(currentLedger) > entry.Expiration.ExpirationLedgerSeq {
currentLedger := result.LatestLedger + 1
if xdr.Uint32(currentLedger) > expirationLedgerSeq {
expired = true
t.Logf("ledger entry expired")
break
}
t.Log("waiting for ledger entry to expire at ledger", entry.Expiration.ExpirationLedgerSeq)
t.Log("waiting for ledger entry to expire at ledger", expirationLedgerSeq)
time.Sleep(time.Second)
}
require.True(t, expired)
Expand Down

0 comments on commit b4838f8

Please sign in to comment.