std::string message::string() { uint64_t len = varint(); value_type string = static_cast<value_type>(data_); skipBytes(len); return std::string(string, len); }
void kConnection::send_request(const Request& m) { std::string s; m.SerializeToString(&s); stream << varint(s.size()) << s; // TODO: Return future to the response }
void message::skipValue(uint64_t val) { switch (val & 0x7) { case 0: // varint varint(); break; case 1: // 64 bit skipBytes(8); break; case 2: // string/message skipBytes(varint()); break; case 5: // 32 bit skipBytes(4); break; default: char msg[80]; snprintf(msg, 80, "cannot skip unknown type %lld", (unsigned long long)(val & 0x7)); throw std::runtime_error(msg); } }
message message::getMessage() { uint32_t bytes = static_cast<uint32_t>(varint()); value_type pos = data_; skipBytes(bytes); return message(pos, bytes); }
int64_t message::int64() { return (int64_t)varint(); }
int64_t message::svarint() { uint64_t n = varint(); return (n >> 1) ^ -static_cast<int64_t>((n & 1)); }
void net_process() { while (true) { struct bitcoin_msg_header header; if (read_all(sock, (char*)&header, sizeof(header)) != sizeof(header)) return disconnect("failed to read message header"); if (header.magic != BITCOIN_MAGIC) return disconnect("invalid magic bytes"); struct timeval start_read; gettimeofday(&start_read, NULL); header.length = le32toh(header.length); if (header.length > 5000000) return disconnect("got message too large"); auto msg = std::make_shared<std::vector<unsigned char> > (sizeof(struct bitcoin_msg_header) + uint32_t(header.length)); if (read_all(sock, (char*)&(*msg)[sizeof(struct bitcoin_msg_header)], header.length) != int(header.length)) return disconnect("failed to read message"); unsigned char fullhash[32]; CSHA256 hash; hash.Write(&(*msg)[sizeof(struct bitcoin_msg_header)], header.length).Finalize(fullhash); hash.Reset().Write(fullhash, sizeof(fullhash)).Finalize(fullhash); if (memcmp((char*)fullhash, header.checksum, sizeof(header.checksum))) return disconnect("got invalid message checksum"); if (!strncmp(header.command, "version", strlen("version"))) { if (connected != 0) return disconnect("got invalid version"); connected = 1; if (header.length < sizeof(struct bitcoin_version_start)) return disconnect("got short version"); struct bitcoin_version_start *their_version = (struct bitcoin_version_start*) &(*msg)[sizeof(struct bitcoin_msg_header)]; printf("%s Protocol version %u\n", host.c_str(), le32toh(their_version->protocol_version)); struct bitcoin_version_with_header version_msg; version_msg.version.start.timestamp = htole64(time(0)); memcpy(((char*)&version_msg.version.end.user_agent) + 27, location, 7); static_assert(BITCOIN_UA_LENGTH == 27 + 7 + 2 /* 27 + 7 + '/' + '\0' */, "BITCOIN_UA changed in header but file not updated"); prepare_message("version", (unsigned char*)&version_msg, sizeof(struct bitcoin_version)); if (send_all(sock, (char*)&version_msg, sizeof(struct bitcoin_version_with_header)) != sizeof(struct bitcoin_version_with_header)) return disconnect("failed to send version message"); struct bitcoin_msg_header verack_header; prepare_message("verack", (unsigned char*)&verack_header, 0); if (send_all(sock, (char*)&verack_header, sizeof(struct bitcoin_msg_header)) != sizeof(struct bitcoin_msg_header)) return disconnect("failed to send verack"); continue; } else if (!strncmp(header.command, "verack", strlen("verack"))) { if (connected != 1) return disconnect("got invalid verack"); connected = 2; send_mutex.unlock(); continue; } if (connected != 2) return disconnect("got non-version, non-verack before version+verack"); if (!strncmp(header.command, "ping", strlen("ping"))) { memcpy(&header.command, "pong", sizeof("pong")); memcpy(&(*msg)[0], &header, sizeof(struct bitcoin_msg_header)); std::lock_guard<std::mutex> lock(send_mutex); if (send_all(sock, (char*)&(*msg)[0], sizeof(struct bitcoin_msg_header) + header.length) != int64_t(sizeof(struct bitcoin_msg_header) + header.length)) return disconnect("failed to send pong"); continue; } else if (!strncmp(header.command, "inv", strlen("inv"))) { std::lock_guard<std::mutex> lock(send_mutex); try { std::set<std::vector<unsigned char> > setRequestBlocks; std::set<std::vector<unsigned char> > setRequestTxn; std::vector<unsigned char>::const_iterator it = msg->begin(); it += sizeof(struct bitcoin_msg_header); uint64_t count = read_varint(it, msg->end()); if (count > 50000) return disconnect("inv count > MAX_INV_SZ"); uint32_t MSG_TX = htole32(1); uint32_t MSG_BLOCK = htole32(2); for (uint64_t i = 0; i < count; i++) { move_forward(it, 4 + 32, msg->end()); std::vector<unsigned char> hash(it-32, it); const uint32_t type = (*(it-(1+32)) << 24) | (*(it-(2+32)) << 16) | (*(it-(3+32)) << 8) | *(it-(4+32)); if (type == MSG_TX) { if (!txnAlreadySeen.insert(hash).second) continue; setRequestTxn.insert(hash); } else if (type == MSG_BLOCK) { if (!blocksAlreadySeen.insert(hash).second) continue; setRequestBlocks.insert(hash); } else return disconnect("unknown inv type"); } if (setRequestBlocks.size()) { std::vector<unsigned char> getdataMsg; std::vector<unsigned char> invCount = varint(setRequestBlocks.size()); getdataMsg.reserve(sizeof(struct bitcoin_msg_header) + invCount.size() + setRequestBlocks.size()*36); getdataMsg.insert(getdataMsg.end(), sizeof(struct bitcoin_msg_header), 0); getdataMsg.insert(getdataMsg.end(), invCount.begin(), invCount.end()); for (auto& hash : setRequestBlocks) { getdataMsg.insert(getdataMsg.end(), (unsigned char*)&MSG_BLOCK, ((unsigned char*)&MSG_BLOCK) + 4); getdataMsg.insert(getdataMsg.end(), hash.begin(), hash.end()); } prepare_message("getdata", (unsigned char*)&getdataMsg[0], invCount.size() + setRequestBlocks.size()*36); if (send_all(sock, (char*)&getdataMsg[0], sizeof(struct bitcoin_msg_header) + invCount.size() + setRequestBlocks.size()*36) != int(sizeof(struct bitcoin_msg_header) + invCount.size() + setRequestBlocks.size()*36)) return disconnect("error sending getdata"); for (auto& hash : setRequestBlocks) { struct timeval tv; gettimeofday(&tv, NULL); for (unsigned int i = 0; i < hash.size(); i++) printf("%02x", hash[hash.size() - i - 1]); printf(" requested from %s at %lu\n", host.c_str(), uint64_t(tv.tv_sec) * 1000 + uint64_t(tv.tv_usec) / 1000); } } if (setRequestTxn.size()) { std::vector<unsigned char> getdataMsg; std::vector<unsigned char> invCount = varint(setRequestTxn.size()); getdataMsg.reserve(sizeof(struct bitcoin_msg_header) + invCount.size() + setRequestTxn.size()*36); getdataMsg.insert(getdataMsg.end(), sizeof(struct bitcoin_msg_header), 0); getdataMsg.insert(getdataMsg.end(), invCount.begin(), invCount.end()); for (const std::vector<unsigned char>& hash : setRequestTxn) { getdataMsg.insert(getdataMsg.end(), (unsigned char*)&MSG_TX, ((unsigned char*)&MSG_TX) + 4); getdataMsg.insert(getdataMsg.end(), hash.begin(), hash.end()); } prepare_message("getdata", (unsigned char*)&getdataMsg[0], invCount.size() + setRequestTxn.size()*36); if (send_all(sock, (char*)&getdataMsg[0], sizeof(struct bitcoin_msg_header) + invCount.size() + setRequestTxn.size()*36) != int(sizeof(struct bitcoin_msg_header) + invCount.size() + setRequestTxn.size()*36)) return disconnect("error sending getdata"); } } catch (read_exception) { return disconnect("failed to process inv"); } continue; } memcpy(&(*msg)[0], &header, sizeof(struct bitcoin_msg_header)); if (!strncmp(header.command, "block", strlen("block"))) { provide_block(this, msg, start_read); } else if (!strncmp(header.command, "tx", strlen("tx"))) { provide_transaction(this, msg); } } }
const char* SuFunction::mem(int& ci) { int n = varint(code, ci); except_if(n >= nliterals, "n " << n << " nliterals " << nliterals); return literals[n].str(); }
int SuFunction::disasm1(Ostream& out, int ci) { verify(locals); verify(literals); out << "\t\t\t\t\t" << setw(3) << ci << " "; short op = code[ci++]; // out << hex << setw(3) << op << " " << dec; out << opcodes[op] << " "; if (op == I_SUPER) { out << globals(TARGET(ci)); ci += 2; } else if (op == I_EACH) out << (int) code[ci++]; else if (op == I_BLOCK) { out << ci + 2 + TARGET(ci); ci += 2; int first = code[ci++]; int nargs = code[ci++]; for (int i = 0; i < nargs; ++i) out << " " << 1 + symstr(locals[first + i]); } else if (op == I_PUSH_INT) { out << TARGET(ci); ci += 2; } else if (op < 16 || op == I_BOOL) ; else if (op < I_PUSH) { switch (op & 0xf0) { case I_PUSH_LITERAL: out << literals[op & 15]; break; case I_PUSH_AUTO: out << symstr(locals[op & 15]); break; case I_EQ_AUTO: case I_EQ_AUTO_POP: out << symstr(locals[op & 7]); break; case I_CALL_GLOBAL: out << globals(TARGET(ci)) << " " << (op & 7); ci += 2; break; case I_CALL_MEM: case I_CALL_MEM_SELF: out << mem(ci) << " " << (op & 7); break; default: break; } } else if ((op & 0xf8) == I_PUSH) { switch (op & 7) { case LITERAL: out << literals[varint(code, ci)]; break; case AUTO: case DYNAMIC: out << symstr(locals[code[ci++]]); break; case MEM: case MEM_SELF: out << mem(ci); break; case GLOBAL: out << globals(TARGET(ci)); ci += 2; break; default: break; } } else if ((op & 0xf8) == I_CALL) { switch (op & 7) { case AUTO: case DYNAMIC: out << symstr(locals[code[ci++]]); break; case MEM: case MEM_SELF: out << mem(ci); ci += 2; break; case GLOBAL: out << globals(TARGET(ci)); ci += 2; break; default: break; } out << " " << (short) code[ci++]; short nargnames = code[ci++]; out << " " << nargnames; for (int i = 0; i < nargnames; ++i) { out << " " << symstr(TARGET(ci)); ci += 2; } } else if ((op & 0xf8) == I_JUMP || op == I_TRY || op == I_CATCH) { out << ci + 2 + TARGET(ci); ci += 2; if (op == I_TRY) out << " " << literals[varint(code, ci)]; } else if (I_ADDEQ <= op && op < I_ADD) { switch ((op & 0x70) >> 4) { case AUTO: case DYNAMIC: out << symstr(locals[code[ci++]]); break; case MEM: case MEM_SELF: out << mem(ci); break; default: break; } } out << "\n"; return ci; }