Skip to content

Commit

Permalink
Wire up soroban PRNG seed from txset hash, tx and op numbers.
Browse files Browse the repository at this point in the history
  • Loading branch information
graydon committed Jun 12, 2023
1 parent d347617 commit 20cc4e3
Show file tree
Hide file tree
Showing 13 changed files with 97 additions and 34 deletions.
17 changes: 16 additions & 1 deletion src/ledger/LedgerManagerImpl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1294,6 +1294,9 @@ LedgerManagerImpl::applyTransactions(

prefetchTransactionData(txs);

Hash sorobanBasePrngSeed = txSet.getContentsHash();
uint64_t txNum{0};

for (auto tx : txs)
{
ZoneNamedN(txZone, "applyTransaction", true);
Expand All @@ -1303,7 +1306,19 @@ LedgerManagerImpl::applyTransactions(
hexAbbrev(tx->getContentsHash()), tx->getNumOperations(),
tx->getSeqNum(),
mApp.getConfig().toShortString(tx->getSourceID()));
tx->apply(mApp, ltx, tm);

Hash subSeed = sorobanBasePrngSeed;
// If tx can use the seed, we need to compute a sub-seed for it.
if (tx->isSoroban())
{
SHA256 subSeedSha;
subSeedSha.add(sorobanBasePrngSeed);
subSeedSha.add(xdr::xdr_to_opaque(txNum));
subSeed = subSeedSha.finish();
}
++txNum;

tx->apply(mApp, ltx, tm, subSeed);
tx->processPostApply(mApp, ltx, tm);
TransactionResultPair results;
results.transactionHash = tx->getContentsHash();
Expand Down
19 changes: 14 additions & 5 deletions src/rust/src/contract.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,11 +26,11 @@ use super::soroban_env_host::{
},
storage::{self, AccessType, Footprint, FootprintMap, Storage, StorageMap},
xdr::{
self, AccountId, ContractCodeEntryBody, ContractDataEntryBody, ContractEvent,
ContractLedgerEntryType, DiagnosticEvent, HostFunction, LedgerEntry, LedgerEntryData,
LedgerKey, LedgerKeyAccount, LedgerKeyContractCode, LedgerKeyContractData,
LedgerKeyTrustLine, ReadXdr, SorobanResources, WriteXdr, XDR_FILES_SHA256,
ContractCostParams, ContractEventType, ScErrorCode, ScErrorType, SorobanAuthorizationEntry,
self, AccountId, ContractCodeEntryBody, ContractCostParams, ContractDataEntryBody,
ContractEvent, ContractEventType, ContractLedgerEntryType, DiagnosticEvent, HostFunction,
LedgerEntry, LedgerEntryData, LedgerKey, LedgerKeyAccount, LedgerKeyContractCode,
LedgerKeyContractData, LedgerKeyTrustLine, ReadXdr, ScErrorCode, ScErrorType,
SorobanAuthorizationEntry, SorobanResources, WriteXdr, XDR_FILES_SHA256,
},
DiagnosticLevel, Host, HostError, LedgerInfo,
};
Expand Down Expand Up @@ -358,6 +358,7 @@ pub(crate) fn invoke_host_function(
auth_entries: &Vec<CxxBuf>,
ledger_info: CxxLedgerInfo,
ledger_entries: &Vec<CxxBuf>,
base_prng_seed: &CxxBuf,
) -> Result<InvokeHostFunctionOutput, Box<dyn Error>> {
let res = panic::catch_unwind(panic::AssertUnwindSafe(|| {
invoke_host_function_or_maybe_panic(
Expand All @@ -368,6 +369,7 @@ pub(crate) fn invoke_host_function(
auth_entries,
ledger_info,
ledger_entries,
base_prng_seed,
)
}));
match res {
Expand All @@ -384,6 +386,7 @@ fn invoke_host_function_or_maybe_panic(
auth_entries: &Vec<CxxBuf>,
ledger_info: CxxLedgerInfo,
ledger_entries: &Vec<CxxBuf>,
base_prng_seed: &CxxBuf,
) -> Result<InvokeHostFunctionOutput, Box<dyn Error>> {
let hf = xdr_from_cxx_buf::<HostFunction>(&hf_buf)?;
let source_account = xdr_from_cxx_buf::<AccountId>(&source_account_buf)?;
Expand All @@ -403,6 +406,12 @@ fn invoke_host_function_or_maybe_panic(
host.set_source_account(source_account);
host.set_ledger_info(ledger_info.into());
host.set_authorization_entries(auth_entries)?;
let seed32: [u8; 32] = base_prng_seed
.data
.as_slice()
.try_into()
.map_err(|_| CoreHostError::General("Wrong base PRNG seed size"))?;
host.set_base_prng_seed(seed32);
if enable_diagnostics {
host.set_diagnostic_level(DiagnosticLevel::Debug);
}
Expand Down
4 changes: 4 additions & 0 deletions src/rust/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -141,6 +141,7 @@ mod rust_bridge {
auth_entries: &Vec<CxxBuf>,
ledger_info: CxxLedgerInfo,
ledger_entries: &Vec<CxxBuf>,
base_prng_seed: &CxxBuf,
) -> Result<InvokeHostFunctionOutput>;
fn init_logging(maxLevel: LogLevel) -> Result<()>;

Expand Down Expand Up @@ -538,6 +539,7 @@ pub(crate) fn invoke_host_function(
auth_entries: &Vec<CxxBuf>,
ledger_info: CxxLedgerInfo,
ledger_entries: &Vec<CxxBuf>,
base_prng_seed: &CxxBuf,
) -> Result<InvokeHostFunctionOutput, Box<dyn std::error::Error>> {
if ledger_info.protocol_version > config_max_protocol {
return Err(Box::new(soroban_curr::contract::CoreHostError::General(
Expand All @@ -555,6 +557,7 @@ pub(crate) fn invoke_host_function(
auth_entries,
ledger_info,
ledger_entries,
base_prng_seed,
);
}
}
Expand All @@ -566,6 +569,7 @@ pub(crate) fn invoke_host_function(
auth_entries,
ledger_info,
ledger_entries,
base_prng_seed,
)
}

Expand Down
2 changes: 1 addition & 1 deletion src/test/FuzzerImpl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -880,7 +880,7 @@ class FuzzTransactionFrame : public TransactionFrame
loadSourceAccount(ltx, ltx.loadHeader());
processSeqNum(ltx);
TransactionMetaFrame tm(2);
applyOperations(signatureChecker, app, ltx, tm);
applyOperations(signatureChecker, app, ltx, tm, Hash{});
if (getResultCode() == txINTERNAL_ERROR)
{
throw std::runtime_error("Internal error while fuzzing");
Expand Down
5 changes: 3 additions & 2 deletions src/transactions/FeeBumpTransactionFrame.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -114,7 +114,8 @@ updateResult(TransactionResult& outerRes, TransactionFrameBasePtr innerTx)

bool
FeeBumpTransactionFrame::apply(Application& app, AbstractLedgerTxn& ltx,
TransactionMetaFrame& meta)
TransactionMetaFrame& meta,
Hash const& sorobanBasePrngSeed)
{
try
{
Expand All @@ -137,7 +138,7 @@ FeeBumpTransactionFrame::apply(Application& app, AbstractLedgerTxn& ltx,

try
{
bool res = mInnerTx->apply(app, ltx, meta, false);
bool res = mInnerTx->apply(app, ltx, meta, false, sorobanBasePrngSeed);
// If this throws, then we may not have the correct TransactionResult so
// we must crash.
updateResult(getResult(), mInnerTx);
Expand Down
3 changes: 2 additions & 1 deletion src/transactions/FeeBumpTransactionFrame.h
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,8 @@ class FeeBumpTransactionFrame : public TransactionFrameBase
virtual ~FeeBumpTransactionFrame(){};

bool apply(Application& app, AbstractLedgerTxn& ltx,
TransactionMetaFrame& meta) override;
TransactionMetaFrame& meta,
Hash const& sorobanBasePrngSeed) override;

void processPostApply(Application& app, AbstractLedgerTxn& ltx,
TransactionMetaFrame& meta) override;
Expand Down
13 changes: 10 additions & 3 deletions src/transactions/InvokeHostFunctionOpFrame.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -116,7 +116,8 @@ InvokeHostFunctionOpFrame::isOpSupported(LedgerHeader const& header) const
bool
InvokeHostFunctionOpFrame::doApply(AbstractLedgerTxn& ltx)
{
throw std::runtime_error("InvokeHostFunctionOpFrame::doApply needs Config");
throw std::runtime_error(
"InvokeHostFunctionOpFrame::doApply needs Config and base PRNG seed");
}

void
Expand Down Expand Up @@ -269,7 +270,8 @@ struct HostFunctionMetrics
};

bool
InvokeHostFunctionOpFrame::doApply(Application& app, AbstractLedgerTxn& ltx)
InvokeHostFunctionOpFrame::doApply(Application& app, AbstractLedgerTxn& ltx,
Hash const& sorobanBasePrngSeed)
{
Config const& cfg = app.getConfig();
HostFunctionMetrics metrics(app.getMetrics());
Expand Down Expand Up @@ -355,12 +357,17 @@ InvokeHostFunctionOpFrame::doApply(Application& app, AbstractLedgerTxn& ltx)
try
{
auto timeScope = metrics.getExecTimer();
CxxBuf basePrngSeedBuf;
basePrngSeedBuf.data = std::make_unique<std::vector<uint8_t>>();
basePrngSeedBuf.data->assign(sorobanBasePrngSeed.begin(),
sorobanBasePrngSeed.end());

out = rust_bridge::invoke_host_function(
cfg.CURRENT_LEDGER_PROTOCOL_VERSION,
cfg.ENABLE_SOROBAN_DIAGNOSTIC_EVENTS, hostFnCxxBuf,
toCxxBuf(resources), toCxxBuf(getSourceID()), authEntryCxxBufs,
getLedgerInfo(ltx, cfg, sorobanConfig), ledgerEntryCxxBufs);
getLedgerInfo(ltx, cfg, sorobanConfig), ledgerEntryCxxBufs,
basePrngSeedBuf);

if (out.success)
{
Expand Down
3 changes: 2 additions & 1 deletion src/transactions/InvokeHostFunctionOpFrame.h
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,8 @@ class InvokeHostFunctionOpFrame : public OperationFrame
bool isOpSupported(LedgerHeader const& header) const override;

bool doApply(AbstractLedgerTxn& ltx) override;
bool doApply(Application& app, AbstractLedgerTxn& ltx) override;
bool doApply(Application& app, AbstractLedgerTxn& ltx,
Hash const& sorobanBasePrngSeed) override;

bool doCheckValid(SorobanNetworkConfig const& config,
uint32_t ledgerVersion) override;
Expand Down
11 changes: 6 additions & 5 deletions src/transactions/OperationFrame.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -135,26 +135,27 @@ OperationFrame::OperationFrame(Operation const& op, OperationResult& res,

bool
OperationFrame::apply(Application& app, SignatureChecker& signatureChecker,
AbstractLedgerTxn& ltx)
AbstractLedgerTxn& ltx, Hash const& sorobanBasePrngSeed)
{
ZoneScoped;
bool res;
CLOG_TRACE(Tx, "{}", xdr_to_string(mOperation, "Operation"));
res = checkValid(app, signatureChecker, ltx, true);
if (res)
{
res = doApply(app, ltx);
res = doApply(app, ltx, sorobanBasePrngSeed);
CLOG_TRACE(Tx, "{}", xdr_to_string(mResult, "OperationResult"));
}

return res;
}

bool
OperationFrame::doApply(Application& _app, AbstractLedgerTxn& ltx)
OperationFrame::doApply(Application& _app, AbstractLedgerTxn& ltx,
Hash const& sorobanBasePrngSeed)
{
// By default we ignore the app, but subclasses can override to
// intercept and use it.
// By default we ignore the app and seed, but subclasses can override to
// intercept and use them.
return doApply(ltx);
}

Expand Down
5 changes: 3 additions & 2 deletions src/transactions/OperationFrame.h
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,8 @@ class OperationFrame
uint32_t ledgerVersion);
virtual bool doCheckValid(uint32_t ledgerVersion) = 0;

virtual bool doApply(Application& app, AbstractLedgerTxn& ltx);
virtual bool doApply(Application& app, AbstractLedgerTxn& ltx,
Hash const& sorobanBasePrngSeed);
virtual bool doApply(AbstractLedgerTxn& ltx) = 0;

// returns the threshold this operation requires
Expand Down Expand Up @@ -88,7 +89,7 @@ class OperationFrame
AbstractLedgerTxn& ltxOuter, bool forApply);

bool apply(Application& app, SignatureChecker& signatureChecker,
AbstractLedgerTxn& ltx);
AbstractLedgerTxn& ltx, Hash const& sorobanBasePrngSeed);

Operation const&
getOperation() const
Expand Down
34 changes: 26 additions & 8 deletions src/transactions/TransactionFrame.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1335,16 +1335,18 @@ TransactionFrame::markResultFailed()
}

bool
TransactionFrame::apply(Application& app, AbstractLedgerTxn& ltx)
TransactionFrame::apply(Application& app, AbstractLedgerTxn& ltx,
Hash const& sorobanBasePrngSeed)
{
TransactionMetaFrame tm(ltx.loadHeader().current().ledgerVersion);
return apply(app, ltx, tm);
return apply(app, ltx, tm, sorobanBasePrngSeed);
}

bool
TransactionFrame::applyOperations(SignatureChecker& signatureChecker,
Application& app, AbstractLedgerTxn& ltx,
TransactionMetaFrame& outerMeta)
TransactionMetaFrame& outerMeta,
Hash const& sorobanBasePrngSeed)
{
ZoneScoped;
auto& internalErrorCounter = app.getMetrics().NewCounter(
Expand All @@ -1369,11 +1371,24 @@ TransactionFrame::applyOperations(SignatureChecker& signatureChecker,
auto& opTimer =
app.getMetrics().NewTimer({"ledger", "operation", "apply"});

uint64_t opNum{0};
for (auto& op : mOperations)
{
auto time = opTimer.TimeScope();
LedgerTxn ltxOp(ltxTx);
bool txRes = op->apply(app, signatureChecker, ltxOp);

Hash subSeed = sorobanBasePrngSeed;
// If op can use the seed, we need to compute a sub-seed for it.
if (op->isSoroban())
{
SHA256 subSeedSha;
subSeedSha.add(sorobanBasePrngSeed);
subSeedSha.add(xdr::xdr_to_opaque(opNum));
subSeed = subSeedSha.finish();
}
++opNum;

bool txRes = op->apply(app, signatureChecker, ltxOp, subSeed);

if (!txRes)
{
Expand Down Expand Up @@ -1690,7 +1705,8 @@ TransactionFrame::applyExpirationBumps(Application& app, AbstractLedgerTxn& ltx)

bool
TransactionFrame::apply(Application& app, AbstractLedgerTxn& ltx,
TransactionMetaFrame& meta, bool chargeFee)
TransactionMetaFrame& meta, bool chargeFee,
Hash const& sorobanBasePrngSeed)
{
ZoneScoped;
try
Expand Down Expand Up @@ -1724,7 +1740,8 @@ TransactionFrame::apply(Application& app, AbstractLedgerTxn& ltx,
// have the correct TransactionResult so we must crash.
if (ok)
{
ok = applyOperations(signatureChecker, app, ltx, meta);
ok = applyOperations(signatureChecker, app, ltx, meta,
sorobanBasePrngSeed);
}
return ok;
}
Expand Down Expand Up @@ -1753,9 +1770,10 @@ TransactionFrame::apply(Application& app, AbstractLedgerTxn& ltx,

bool
TransactionFrame::apply(Application& app, AbstractLedgerTxn& ltx,
TransactionMetaFrame& meta)
TransactionMetaFrame& meta,
Hash const& sorobanBasePrngSeed)
{
return apply(app, ltx, meta, true);
return apply(app, ltx, meta, true, sorobanBasePrngSeed);
}

void
Expand Down
12 changes: 8 additions & 4 deletions src/transactions/TransactionFrame.h
Original file line number Diff line number Diff line change
Expand Up @@ -119,7 +119,8 @@ class TransactionFrame : public TransactionFrameBase
void markResultFailed();

bool applyOperations(SignatureChecker& checker, Application& app,
AbstractLedgerTxn& ltx, TransactionMetaFrame& meta);
AbstractLedgerTxn& ltx, TransactionMetaFrame& meta,
Hash const& sorobanBasePrngSeed);

bool applyExpirationBumps(Application& app, AbstractLedgerTxn& ltx);

Expand Down Expand Up @@ -246,9 +247,11 @@ class TransactionFrame : public TransactionFrameBase
// apply this transaction to the current ledger
// returns true if successfully applied
bool apply(Application& app, AbstractLedgerTxn& ltx,
TransactionMetaFrame& meta, bool chargeFee);
TransactionMetaFrame& meta, bool chargeFee,
Hash const& sorobanBasePrngSeed);
bool apply(Application& app, AbstractLedgerTxn& ltx,
TransactionMetaFrame& meta) override;
TransactionMetaFrame& meta,
Hash const& sorobanBasePrngSeed = Hash{}) override;

// Performs the necessary post-apply transaction processing.
// This has to be called after both `processFeeSeqNum` and
Expand All @@ -258,7 +261,8 @@ class TransactionFrame : public TransactionFrameBase
TransactionMetaFrame& meta) override;

// version without meta
bool apply(Application& app, AbstractLedgerTxn& ltx);
bool apply(Application& app, AbstractLedgerTxn& ltx,
Hash const& sorobanBasePrngSeed);

StellarMessage toStellarMessage() const override;

Expand Down
3 changes: 2 additions & 1 deletion src/transactions/TransactionFrameBase.h
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,8 @@ class TransactionFrameBase
TransactionEnvelope const& env);

virtual bool apply(Application& app, AbstractLedgerTxn& ltx,
TransactionMetaFrame& meta) = 0;
TransactionMetaFrame& meta,
Hash const& sorobanBasePrngSeed = Hash{}) = 0;

virtual bool checkValid(Application& app, AbstractLedgerTxn& ltxOuter,
SequenceNumber current,
Expand Down

5 comments on commit 20cc4e3

@latobarita
Copy link
Contributor

Choose a reason for hiding this comment

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

saw approval from dmkozh
at graydon@20cc4e3

@latobarita
Copy link
Contributor

Choose a reason for hiding this comment

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

merging graydon/stellar-core/set-base-prng-seed = 20cc4e3 into auto

@latobarita
Copy link
Contributor

Choose a reason for hiding this comment

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

graydon/stellar-core/set-base-prng-seed = 20cc4e3 merged ok, testing candidate = 97ba212

@latobarita
Copy link
Contributor

Choose a reason for hiding this comment

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

fast-forwarding master to auto = 97ba212

Please sign in to comment.