Skip to content

Commit fdf7a7a

Browse files
authored
Merge pull request #110 from dfeen87/copilot/impl-bitcoin-shadow-mode-safety
Enforce Bitcoin mainnet shadow mode by default
2 parents 1876bb5 + 8246237 commit fdf7a7a

5 files changed

Lines changed: 56 additions & 1 deletion

File tree

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313

1414
# Build folder
1515
build/
16+
build_write_enabled/
1617
bin/
1718
out/
1819
_codeql_build_dir/

CMakeLists.txt

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -396,6 +396,19 @@ elseif(ZeroMQ_LIBRARY)
396396
target_compile_definitions(ailee_adapters PRIVATE AILEE_HAS_ZMQ=1)
397397
endif()
398398

399+
# ============================================================================
400+
# Bitcoin Write Safety Gate
401+
# ============================================================================
402+
403+
option(AILEE_BITCOIN_WRITE_ENABLED "Enable Bitcoin write operations (sendrawtransaction, sign, etc.)" OFF)
404+
if(NOT AILEE_BITCOIN_WRITE_ENABLED)
405+
target_compile_definitions(ailee_node PRIVATE AILEE_BITCOIN_WRITE_DISABLED=1)
406+
target_compile_definitions(ailee_adapters PRIVATE AILEE_BITCOIN_WRITE_DISABLED=1)
407+
message(STATUS "Bitcoin write operations: DISABLED (shadow/read-only mode)")
408+
else()
409+
message(STATUS "Bitcoin write operations: ENABLED")
410+
endif()
411+
399412
# ============================================================================
400413
# Unit Tests (Optional)
401414
# ============================================================================

include/Global_Seven.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -240,7 +240,7 @@ struct AdapterConfig {
240240
std::string network; // "mainnet", "testnet", "devnet"
241241
std::unordered_map<std::string, std::string> extra; // per‑chain params
242242
bool enableTelemetry{true};
243-
bool readOnly{false}; // listen‑only
243+
bool readOnly{true}; // listen‑only (default: shadow/read-only mode)
244244
FeePolicy feePolicy{};
245245
SlippagePolicy slippagePolicy{};
246246
double minOracleConfidence{0.7};

src/l1/BitcoinAdapter.cpp

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -305,6 +305,13 @@ class BitcoinTxBuilder {
305305
const std::vector<TxOut>& outputs,
306306
const std::unordered_map<std::string, std::string>& opts
307307
) {
308+
#if defined(AILEE_BITCOIN_WRITE_DISABLED)
309+
(void)rpc; (void)outputs; (void)opts;
310+
throw std::runtime_error(
311+
"Bitcoin write operations disabled at compile time "
312+
"(AILEE_BITCOIN_WRITE_DISABLED). "
313+
"Rebuild with -DAILEE_BITCOIN_WRITE_ENABLED=ON to enable.");
314+
#else
308315
// Get UTXOs
309316
Json::Value utxosJson = rpc.call("listunspent", Json::Value(Json::arrayValue));
310317

@@ -365,6 +372,7 @@ class BitcoinTxBuilder {
365372
}
366373

367374
return signedTx["hex"].asString();
375+
#endif
368376
}
369377
};
370378

@@ -515,6 +523,20 @@ class BTCInternal {
515523
bool broadcastRaw(const std::string& rawHex,
516524
std::string& outTxId,
517525
ErrorCallback onError) {
526+
#if defined(AILEE_BITCOIN_WRITE_DISABLED)
527+
(void)rawHex; (void)outTxId;
528+
if (onError) {
529+
onError(AdapterError{
530+
Severity::Error,
531+
"Bitcoin write operations disabled at compile time "
532+
"(AILEE_BITCOIN_WRITE_DISABLED). "
533+
"Rebuild with -DAILEE_BITCOIN_WRITE_ENABLED=ON to enable.",
534+
"Broadcast",
535+
-12
536+
});
537+
}
538+
return false;
539+
#else
518540
try {
519541
// Check if already broadcast (idempotency)
520542
std::lock_guard<std::mutex> lock(broadcastMutex_);
@@ -550,6 +572,7 @@ class BTCInternal {
550572
}
551573
return false;
552574
}
575+
#endif
553576
}
554577

555578
std::optional<NormalizedTx> fetchTx(const std::string& txid, ErrorCallback onError) {

tests/AdapterRegistryTests.cpp

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -99,3 +99,21 @@ TEST(AdapterRegistryTest, GetBlockHeightReturnsValue) {
9999
ASSERT_TRUE(h.has_value());
100100
EXPECT_EQ(h.value(), 42ULL);
101101
}
102+
103+
TEST(AdapterConfigTest, ReadOnlyDefaultIsTrue) {
104+
AdapterConfig cfg;
105+
EXPECT_TRUE(cfg.readOnly);
106+
}
107+
108+
#if defined(AILEE_BITCOIN_WRITE_DISABLED)
109+
TEST(BitcoinShadowModeTest, WriteDisabledAtCompileTime) {
110+
// When AILEE_BITCOIN_WRITE_DISABLED is set, the macro is active.
111+
// This test documents that the compile-time gate is in effect.
112+
EXPECT_TRUE(true);
113+
}
114+
#else
115+
TEST(BitcoinShadowModeTest, WriteEnabledAtCompileTime) {
116+
// AILEE_BITCOIN_WRITE_ENABLED=ON was set; write ops are compiled in.
117+
EXPECT_TRUE(true);
118+
}
119+
#endif

0 commit comments

Comments
 (0)