Skip to content

Commit 3d00a8d

Browse files
committed
Fix scriptSig push opcodes: wrap MM and tag in PUSH_N opcodes matching p2pool
p2pool's create_push_script wraps each element in a push opcode: PUSH_3<height> PUSH_44<mm_data> PUSH_8<tag>. c2pool was concatenating raw bytes without push opcodes. Fixed both build_coinbase_parts and build_connection_coinbase to add push opcode prefixes. Remaining: GENTX-FAIL persists — p2pool reads m_coinbase as 44 bytes but c2pool writes 49 bytes. Wire format deserialization offset issue in the share_type wrapping share_info.
1 parent 07966b7 commit 3d00a8d

1 file changed

Lines changed: 33 additions & 8 deletions

File tree

src/core/web_server.cpp

Lines changed: 33 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1156,7 +1156,12 @@ MiningInterface::build_coinbase_parts(
11561156
}
11571157

11581158
// ScriptSig: height + mm_commitment + tag + state_root (NO extranonce!)
1159-
const int script_total = height_bytes + mm_bytes + tag_bytes + state_root_bytes;
1159+
// Each element (mm, tag) gets a 1-byte push opcode prefix (matching create_push_script)
1160+
// state_root is raw (no push opcode, like coinbaseflags in p2pool)
1161+
const int mm_push_overhead = (mm_bytes > 0) ? 1 : 0;
1162+
const int tag_push_overhead = (tag_bytes > 0) ? 1 : 0;
1163+
const int script_total = height_bytes + mm_push_overhead + mm_bytes
1164+
+ tag_push_overhead + tag_bytes + state_root_bytes;
11601165

11611166
// Build coinb1: entire coinbase TX up to and including ref_hash in OP_RETURN
11621167
std::ostringstream coinb1;
@@ -1167,10 +1172,17 @@ MiningInterface::build_coinbase_parts(
11671172
<< std::hex << std::setfill('0') << std::setw(2) << script_total
11681173
<< height_hex;
11691174

1170-
// scriptSig: mm + tag + state_root (no en1/en2 — those go into last_txout_nonce)
1171-
if (!mm_hex.empty())
1172-
coinb1 << mm_hex;
1173-
coinb1 << tag_hex;
1175+
// scriptSig elements with push opcodes (matching p2pool's create_push_script):
1176+
// Each datum gets its own length-prefix push opcode.
1177+
auto emit_push = [&](std::ostringstream& os, const std::string& data_hex) {
1178+
size_t len = data_hex.size() / 2;
1179+
if (len > 0 && len < 76)
1180+
os << std::hex << std::setfill('0') << std::setw(2) << len;
1181+
os << data_hex;
1182+
};
1183+
if (!mm_hex.empty()) emit_push(coinb1, mm_hex);
1184+
if (!tag_hex.empty()) emit_push(coinb1, tag_hex);
1185+
// state_root appended raw (like p2pool's coinbaseflags)
11741186
if (!state_root_hex.empty())
11751187
coinb1 << state_root_hex;
11761188
coinb1 << "ffffffff"; // sequence = 0xFFFFFFFF
@@ -1331,9 +1343,22 @@ MiningInterface::build_connection_coinbase(
13311343
}
13321344
}
13331345

1334-
// ScriptSig: height + mm + tag + state_root (NO extranonce!)
1335-
// Must match what build_coinbase_parts produces in the actual coinbase.
1336-
std::string scriptsig_hex = height_hex + mm_hex + tag_hex + state_root_hex;
1346+
// ScriptSig: height_push + mm_push + tag_push + state_root (NO extranonce!)
1347+
// Must match p2pool's create_push_script([height, mm_data, coinb_texts]):
1348+
// Each element gets its own push opcode prefix (PUSH_N for N < 76 bytes).
1349+
// state_root is appended as raw bytes (like coinbaseflags in p2pool).
1350+
auto push_prefix = [&](const std::string& data_hex) -> std::string {
1351+
size_t len = data_hex.size() / 2;
1352+
if (len == 0) return "";
1353+
char buf[3];
1354+
snprintf(buf, sizeof(buf), "%02x", static_cast<unsigned>(len));
1355+
return std::string(buf) + data_hex;
1356+
};
1357+
std::string scriptsig_hex = height_hex;
1358+
if (!mm_hex.empty()) scriptsig_hex += push_prefix(mm_hex);
1359+
if (!tag_hex.empty()) scriptsig_hex += push_prefix(tag_hex);
1360+
// state_root appended raw (like p2pool's coinbaseflags + COINBASEEXT)
1361+
scriptsig_hex += state_root_hex;
13371362

13381363
// Decode to bytes for ref_hash computation
13391364
std::vector<unsigned char> scriptsig_bytes;

0 commit comments

Comments
 (0)