std::string hexPrefixEncode(bytesConstRef _d1, unsigned _o1, bytesConstRef _d2, unsigned _o2, bool _leaf) { unsigned begin1 = _o1; unsigned end1 = _d1.size() * 2; unsigned begin2 = _o2; unsigned end2 = _d2.size() * 2; bool odd = (end1 - begin1 + end2 - begin2) & 1; std::string ret(1, ((_leaf ? 2 : 0) | (odd ? 1 : 0)) * 16); ret.reserve((end1 - begin1 + end2 - begin2) / 2 + 1); unsigned d = odd ? 1 : 2; for (auto i = begin1; i < end1; ++i, ++d) { byte n = nibble(_d1, i); if (d & 1) // odd ret.back() |= n; // or the nibble onto the back else ret.push_back(n << 4); // push the nibble on to the back << 4 } for (auto i = begin2; i < end2; ++i, ++d) { byte n = nibble(_d2, i); if (d & 1) // odd ret.back() |= n; // or the nibble onto the back else ret.push_back(n << 4); // push the nibble on to the back << 4 } return ret; }
bool Session::checkPacket(bytesConstRef _msg) { if (_msg[0] > 0x7f || _msg.size() < 2) return false; if (RLP(_msg.cropped(1)).actualSize() + 1 != _msg.size()) return false; return true; }
unique_ptr<DiscoveryDatagram> DiscoveryDatagram::interpretUDP(bi::udp::endpoint const& _from, bytesConstRef _packet) { unique_ptr<DiscoveryDatagram> decoded; // h256 + Signature + type + RLP (smallest possible packet is empty neighbours packet which is 3 bytes) if (_packet.size() < h256::size + Signature::size + 1 + 3) { LOG(g_discoveryWarnLogger::get()) << "Invalid packet (too small) from " << _from.address().to_string() << ":" << _from.port(); return decoded; } bytesConstRef hashedBytes(_packet.cropped(h256::size, _packet.size() - h256::size)); bytesConstRef signedBytes(hashedBytes.cropped(Signature::size, hashedBytes.size() - Signature::size)); bytesConstRef signatureBytes(_packet.cropped(h256::size, Signature::size)); bytesConstRef bodyBytes(_packet.cropped(h256::size + Signature::size + 1)); h256 echo(sha3(hashedBytes)); if (!_packet.cropped(0, h256::size).contentsEqual(echo.asBytes())) { LOG(g_discoveryWarnLogger::get()) << "Invalid packet (bad hash) from " << _from.address().to_string() << ":" << _from.port(); return decoded; } Public sourceid(dev::recover(*(Signature const*)signatureBytes.data(), sha3(signedBytes))); if (!sourceid) { LOG(g_discoveryWarnLogger::get()) << "Invalid packet (bad signature) from " << _from.address().to_string() << ":" << _from.port(); return decoded; } switch (signedBytes[0]) { case PingNode::type: decoded.reset(new PingNode(_from, sourceid, echo)); break; case Pong::type: decoded.reset(new Pong(_from, sourceid, echo)); break; case FindNode::type: decoded.reset(new FindNode(_from, sourceid, echo)); break; case Neighbours::type: decoded.reset(new Neighbours(_from, sourceid, echo)); break; default: LOG(g_discoveryWarnLogger::get()) << "Invalid packet (unknown packet type) from " << _from.address().to_string() << ":" << _from.port(); return decoded; } decoded->interpretRLP(bodyBytes); return decoded; }
void Secp256k1PP::encryptECIES(Public const& _k, bytesConstRef _sharedMacData, bytes& io_cipher) { // interop w/go ecies implementation auto r = KeyPair::create(); Secret z; ecdh::agree(r.sec(), _k, z); auto key = eciesKDF(z, bytes(), 32); bytesConstRef eKey = bytesConstRef(&key).cropped(0, 16); bytesRef mKeyMaterial = bytesRef(&key).cropped(16, 16); CryptoPP::SHA256 ctx; ctx.Update(mKeyMaterial.data(), mKeyMaterial.size()); bytes mKey(32); ctx.Final(mKey.data()); bytes cipherText = encryptSymNoAuth(SecureFixedHash<16>(eKey), h128(), bytesConstRef(&io_cipher)); if (cipherText.empty()) return; bytes msg(1 + Public::size + h128::size + cipherText.size() + 32); msg[0] = 0x04; r.pub().ref().copyTo(bytesRef(&msg).cropped(1, Public::size)); bytesRef msgCipherRef = bytesRef(&msg).cropped(1 + Public::size + h128::size, cipherText.size()); bytesConstRef(&cipherText).copyTo(msgCipherRef); // tag message CryptoPP::HMAC<SHA256> hmacctx(mKey.data(), mKey.size()); bytesConstRef cipherWithIV = bytesRef(&msg).cropped(1 + Public::size, h128::size + cipherText.size()); hmacctx.Update(cipherWithIV.data(), cipherWithIV.size()); hmacctx.Update(_sharedMacData.data(), _sharedMacData.size()); hmacctx.Final(msg.data() + 1 + Public::size + cipherWithIV.size()); io_cipher.resize(msg.size()); io_cipher.swap(msg); }
void eth::sha3(bytesConstRef _input, bytesRef _output) { CryptoPP::SHA3_256 ctx; ctx.Update((byte*)_input.data(), _input.size()); assert(_output.size() >= 32); ctx.Final(_output.data()); }
void dev::writeFile(std::string const& _file, bytesConstRef _data, bool _writeDeleteRename) { namespace fs = boost::filesystem; if (_writeDeleteRename) { fs::path tempPath = fs::unique_path(_file + "-%%%%%%"); writeFile(tempPath.string(), _data, false); // will delete _file if it exists fs::rename(tempPath, _file); } else { // create directory if not existent fs::path p(_file); if (!fs::exists(p.parent_path())) { fs::create_directories(p.parent_path()); DEV_IGNORE_EXCEPTIONS(fs::permissions(p.parent_path(), fs::owner_all)); } ofstream s(_file, ios::trunc | ios::binary); s.write(reinterpret_cast<char const*>(_data.data()), _data.size()); if (!s) BOOST_THROW_EXCEPTION(FileError() << errinfo_comment("Could not write to file: " + _file)); DEV_IGNORE_EXCEPTIONS(fs::permissions(_file, fs::owner_read|fs::owner_write)); } }
bytes dev::aesDecrypt(bytesConstRef _ivCipher, std::string const& _password, unsigned _rounds, bytesConstRef _salt) { bytes pw = asBytes(_password); if (!_salt.size()) _salt = &pw; bytes target(64); CryptoPP::PKCS5_PBKDF2_HMAC<CryptoPP::SHA256>().DeriveKey(target.data(), target.size(), 0, pw.data(), pw.size(), _salt.data(), _salt.size(), _rounds); try { CryptoPP::AES::Decryption aesDecryption(target.data(), 16); auto cipher = _ivCipher.cropped(16); auto iv = _ivCipher.cropped(0, 16); CryptoPP::CBC_Mode_ExternalCipher::Decryption cbcDecryption(aesDecryption, iv.data()); std::string decrypted; CryptoPP::StreamTransformationFilter stfDecryptor(cbcDecryption, new CryptoPP::StringSink(decrypted)); stfDecryptor.Put(cipher.data(), cipher.size()); stfDecryptor.MessageEnd(); return asBytes(decrypted); } catch (exception const& e) { cerr << e.what() << endl; return bytes(); } }
RLP::RLP(bytesConstRef _d, Strictness _s): m_data(_d) { if ((_s & FailIfTooBig) && actualSize() < _d.size()) { if (_s & ThrowOnFail) BOOST_THROW_EXCEPTION(OversizeRLP()); else m_data.reset(); } if ((_s & FailIfTooSmall) && actualSize() > _d.size()) { if (_s & ThrowOnFail) BOOST_THROW_EXCEPTION(UndersizeRLP()); else m_data.reset(); } }
static bytes randomWord(bytesConstRef _alphabet, unsigned _min, unsigned _diff, h256* _seed) { assert(_min + _diff < 33); *_seed = sha3(*_seed); unsigned l = _min + (*_seed)[31] % (_diff + 1); bytes ret; for (unsigned i = 0; i < l; ++i) ret.push_back(_alphabet[(*_seed)[i] % _alphabet.size()]); return ret; }
bool Secp256k1PP::decryptECIES(Secret const& _k, bytesConstRef _sharedMacData, bytes& io_text) { // interop w/go ecies implementation // io_cipher[0] must be 2, 3, or 4, else invalidpublickey if (io_text.empty() || io_text[0] < 2 || io_text[0] > 4) // invalid message: publickey return false; if (io_text.size() < (1 + Public::size + h128::size + 1 + h256::size)) // invalid message: length return false; Secret z; if (!ecdh::agree(_k, *(Public*)(io_text.data() + 1), z)) return false; // Invalid pubkey or seckey. auto key = ecies::kdf(z, bytes(), 64); bytesConstRef eKey = bytesConstRef(&key).cropped(0, 16); bytesRef mKeyMaterial = bytesRef(&key).cropped(16, 16); bytes mKey(32); CryptoPP::SHA256 ctx; ctx.Update(mKeyMaterial.data(), mKeyMaterial.size()); ctx.Final(mKey.data()); bytes plain; size_t cipherLen = io_text.size() - 1 - Public::size - h128::size - h256::size; bytesConstRef cipherWithIV(io_text.data() + 1 + Public::size, h128::size + cipherLen); bytesConstRef cipherIV = cipherWithIV.cropped(0, h128::size); bytesConstRef cipherNoIV = cipherWithIV.cropped(h128::size, cipherLen); bytesConstRef msgMac(cipherNoIV.data() + cipherLen, h256::size); h128 iv(cipherIV.toBytes()); // verify tag CryptoPP::HMAC<CryptoPP::SHA256> hmacctx(mKey.data(), mKey.size()); hmacctx.Update(cipherWithIV.data(), cipherWithIV.size()); hmacctx.Update(_sharedMacData.data(), _sharedMacData.size()); h256 mac; hmacctx.Final(mac.data()); for (unsigned i = 0; i < h256::size; i++) if (mac[i] != msgMac[i]) return false; plain = decryptSymNoAuth(SecureFixedHash<16>(eKey), iv, cipherNoIV).makeInsecure(); io_text.resize(plain.size()); io_text.swap(plain); return true; }
//追加内容到文件 void dev::appendFile(std::string const& _file, bytesConstRef _data) { namespace fs = boost::filesystem; // create directory if not existent fs::path p(_file); if (!fs::exists(p.parent_path())) { fs::create_directories(p.parent_path()); DEV_IGNORE_EXCEPTIONS(fs::permissions(p.parent_path(), fs::owner_all)); } ofstream s(_file, ios::app | ios::binary); s.write(reinterpret_cast<char const*>(_data.data()), _data.size()); if (!s) BOOST_THROW_EXCEPTION(FileError() << errinfo_comment("Could not append write to file: " + _file)); DEV_IGNORE_EXCEPTIONS(fs::permissions(_file, fs::owner_read|fs::owner_write)); }
string dev::toBase58(bytesConstRef _d, string const& _alphabet) { auto begin = _d.data(); auto end = _d.data() + _d.size(); // Skip & count leading zeroes. int zeroes = 0; for (; begin != end && !*begin; begin++, zeroes++) {} // Allocate enough space in big-endian base58 representation. // log(256) / log(58), rounded up. std::vector<unsigned char> b58((end - begin) * 138 / 100 + 1); // Process the bytes. while (begin != end) { int carry = *begin; // Apply "b58 = b58 * 256 + ch". for (auto it = b58.rbegin(); it != b58.rend(); it++) { carry += 256 * (*it); *it = carry % 58; carry /= 58; } assert(!carry); begin++; } // Skip leading zeroes in base58 result. auto it = b58.begin(); while (it != b58.end() && !*it) it++; // Translate the result into a string. std::string ret; ret.reserve(zeroes + (b58.end() - it)); ret.assign(zeroes, '1'); while (it != b58.end()) ret += _alphabet[*(it++)]; return ret; }
std::string hexPrefixEncode(bytesConstRef _data, bool _leaf, int _beginNibble, int _endNibble, unsigned _offset) { unsigned begin = _beginNibble + _offset; unsigned end = (_endNibble < 0 ? ((int)(_data.size() * 2 - _offset) + 1) + _endNibble : _endNibble) + _offset; bool odd = (end - begin) & 1; std::string ret(1, ((_leaf ? 2 : 0) | (odd ? 1 : 0)) * 16); ret.reserve((end - begin) / 2 + 1); unsigned d = odd ? 1 : 2; for (auto i = begin; i < end; ++i, ++d) { byte n = nibble(_data, i); if (d & 1) // odd ret.back() |= n; // or the nibble onto the back else ret.push_back(n << 4); // push the nibble on to the back << 4 } return ret; }
bytesSec dev::decryptAES128CTR(bytesConstRef _k, h128 const& _iv, bytesConstRef _cipher) { if (_k.size() != 16 && _k.size() != 24 && _k.size() != 32) return bytesSec(); SecByteBlock key(_k.data(), _k.size()); try { CTR_Mode<AES>::Decryption d; d.SetKeyWithIV(key, key.size(), _iv.data()); bytesSec ret(_cipher.size()); d.ProcessData(ret.writable().data(), _cipher.data(), _cipher.size()); return ret; } catch (CryptoPP::Exception& _e) { cerr << _e.what() << endl; return bytesSec(); } }
bytes dev::encryptAES128CTR(bytesConstRef _k, h128 const& _iv, bytesConstRef _plain) { if (_k.size() != 16 && _k.size() != 24 && _k.size() != 32) return bytes(); SecByteBlock key(_k.data(), _k.size()); try { CTR_Mode<AES>::Encryption e; e.SetKeyWithIV(key, key.size(), _iv.data()); bytes ret(_plain.size()); e.ProcessData(ret.data(), _plain.data(), _plain.size()); return ret; } catch (CryptoPP::Exception& _e) { cerr << _e.what() << endl; return bytes(); } }
bool contains(bytesConstRef _key) const { return _key.size() >= m_ext.size() && !memcmp(_key.data(), m_ext.data(), m_ext.size()); }
ImportResult BlockQueue::import(bytesConstRef _block, BlockChain const& _bc, bool _isOurs) { clog(BlockQueueTraceChannel) << std::this_thread::get_id(); // Check if we already know this block. h256 h = BlockInfo::headerHash(_block); clog(BlockQueueTraceChannel) << "Queuing block" << h << "for import..."; UpgradableGuard l(m_lock); if (m_readySet.count(h) || m_drainingSet.count(h) || m_unknownSet.count(h) || m_knownBad.count(h)) { // Already know about this one. clog(BlockQueueTraceChannel) << "Already known."; return ImportResult::AlreadyKnown; } // VERIFY: populates from the block and checks the block is internally coherent. BlockInfo bi; try { // TODO: quick verify bi.populate(_block); bi.verifyInternals(_block); } catch (Exception const& _e) { cwarn << "Ignoring malformed block: " << diagnostic_information(_e); return ImportResult::Malformed; } clog(BlockQueueTraceChannel) << "Block" << h << "is" << bi.number << "parent is" << bi.parentHash; // Check block doesn't already exist first! if (_bc.isKnown(h)) { cblockq << "Already known in chain."; return ImportResult::AlreadyInChain; } UpgradeGuard ul(l); DEV_INVARIANT_CHECK; // Check it's not in the future (void)_isOurs; if (bi.timestamp > (u256)time(0)/* && !_isOurs*/) { m_future.insert(make_pair((unsigned)bi.timestamp, make_pair(h, _block.toBytes()))); char buf[24]; time_t bit = (unsigned)bi.timestamp; if (strftime(buf, 24, "%X", localtime(&bit)) == 0) buf[0] = '\0'; // empty if case strftime fails clog(BlockQueueTraceChannel) << "OK - queued for future [" << bi.timestamp << "vs" << time(0) << "] - will wait until" << buf; m_unknownSize += _block.size(); m_unknownCount++; m_difficulty += bi.difficulty; bool unknown = !m_readySet.count(bi.parentHash) && !m_drainingSet.count(bi.parentHash) && !_bc.isKnown(bi.parentHash); return unknown ? ImportResult::FutureTimeUnknown : ImportResult::FutureTimeKnown; } else { // We now know it. if (m_knownBad.count(bi.parentHash)) { m_knownBad.insert(bi.hash()); updateBad_WITH_LOCK(bi.hash()); // bad parent; this is bad too, note it as such return ImportResult::BadChain; } else if (!m_readySet.count(bi.parentHash) && !m_drainingSet.count(bi.parentHash) && !_bc.isKnown(bi.parentHash)) { // We don't know the parent (yet) - queue it up for later. It'll get resent to us if we find out about its ancestry later on. clog(BlockQueueTraceChannel) << "OK - queued as unknown parent:" << bi.parentHash; m_unknown.insert(make_pair(bi.parentHash, make_pair(h, _block.toBytes()))); m_unknownSet.insert(h); m_unknownSize += _block.size(); m_difficulty += bi.difficulty; m_unknownCount++; return ImportResult::UnknownParent; } else { // If valid, append to blocks. clog(BlockQueueTraceChannel) << "OK - ready for chain insertion."; DEV_GUARDED(m_verification) m_unverified.push_back(UnverifiedBlock { h, bi.parentHash, _block.toBytes() }); m_moreToVerify.notify_one(); m_readySet.insert(h); m_knownSize += _block.size(); m_difficulty += bi.difficulty; m_knownCount++; noteReady_WITH_LOCK(h); return ImportResult::Success; } } }
void NodeTable::onReceived(UDPSocketFace*, bi::udp::endpoint const& _from, bytesConstRef _packet) { // h256 + Signature + type + RLP (smallest possible packet is empty neighbours packet which is 3 bytes) if (_packet.size() < h256::size + Signature::size + 1 + 3) { clog(NodeTableMessageSummary) << "Invalid Message size from " << _from.address().to_string() << ":" << _from.port(); return; } bytesConstRef hashedBytes(_packet.cropped(h256::size, _packet.size() - h256::size)); h256 hashSigned(sha3(hashedBytes)); if (!_packet.cropped(0, h256::size).contentsEqual(hashSigned.asBytes())) { clog(NodeTableMessageSummary) << "Invalid Message hash from " << _from.address().to_string() << ":" << _from.port(); return; } bytesConstRef signedBytes(hashedBytes.cropped(Signature::size, hashedBytes.size() - Signature::size)); // todo: verify sig via known-nodeid and MDC, or, do ping/pong auth if node/endpoint is unknown/untrusted bytesConstRef sigBytes(_packet.cropped(h256::size, Signature::size)); Public nodeid(dev::recover(*(Signature const*)sigBytes.data(), sha3(signedBytes))); if (!nodeid) { clog(NodeTableMessageSummary) << "Invalid Message signature from " << _from.address().to_string() << ":" << _from.port(); return; } unsigned packetType = signedBytes[0]; if (packetType && packetType < 4) noteActiveNode(nodeid, _from); bytesConstRef rlpBytes(_packet.cropped(h256::size + Signature::size + 1)); RLP rlp(rlpBytes); try { switch (packetType) { case Pong::type: { // clog(NodeTableMessageSummary) << "Received Pong from " << _from.address().to_string() << ":" << _from.port(); Pong in = Pong::fromBytesConstRef(_from, rlpBytes); // whenever a pong is received, check if it's in m_evictions Guard le(x_evictions); for (auto it = m_evictions.begin(); it != m_evictions.end(); it++) if (it->first.first == nodeid && it->first.second > std::chrono::steady_clock::now()) { if (auto n = nodeEntry(it->second)) dropNode(n); if (auto n = node(it->first.first)) addNode(n); it = m_evictions.erase(it); } break; } case Neighbours::type: { Neighbours in = Neighbours::fromBytesConstRef(_from, rlpBytes); // clog(NodeTableMessageSummary) << "Received " << in.nodes.size() << " Neighbours from " << _from.address().to_string() << ":" << _from.port(); for (auto n: in.nodes) noteActiveNode(n.node, bi::udp::endpoint(bi::address::from_string(n.ipAddress), n.port)); break; } case FindNode::type: { // clog(NodeTableMessageSummary) << "Received FindNode from " << _from.address().to_string() << ":" << _from.port(); FindNode in = FindNode::fromBytesConstRef(_from, rlpBytes); vector<shared_ptr<NodeEntry>> nearest = nearestNodeEntries(in.target); static unsigned const nlimit = (m_socketPointer->maxDatagramSize - 11) / 86; for (unsigned offset = 0; offset < nearest.size(); offset += nlimit) { Neighbours out(_from, nearest, offset, nlimit); out.sign(m_secret); m_socketPointer->send(out); } break; } case PingNode::type: { // clog(NodeTableMessageSummary) << "Received PingNode from " << _from.address().to_string() << ":" << _from.port(); PingNode in = PingNode::fromBytesConstRef(_from, rlpBytes); Pong p(_from); p.echo = sha3(rlpBytes); p.sign(m_secret); m_socketPointer->send(p); break; } default: clog(NodeTableWarn) << "Invalid Message, " << hex << packetType << ", received from " << _from.address().to_string() << ":" << dec << _from.port(); return; } } catch (...) { clog(NodeTableWarn) << "Exception processing message from " << _from.address().to_string() << ":" << _from.port(); } }
void NodeTable::onReceived(UDPSocketFace*, bi::udp::endpoint const& _from, bytesConstRef _packet) { // h256 + Signature + type + RLP (smallest possible packet is empty neighbours packet which is 3 bytes) if (_packet.size() < h256::size + Signature::size + 1 + 3) { clog(NodeTableTriviaSummary) << "Invalid message size from " << _from.address().to_string() << ":" << _from.port(); return; } bytesConstRef hashedBytes(_packet.cropped(h256::size, _packet.size() - h256::size)); h256 hashSigned(sha3(hashedBytes)); if (!_packet.cropped(0, h256::size).contentsEqual(hashSigned.asBytes())) { clog(NodeTableTriviaSummary) << "Invalid message hash from " << _from.address().to_string() << ":" << _from.port(); return; } bytesConstRef signedBytes(hashedBytes.cropped(Signature::size, hashedBytes.size() - Signature::size)); // todo: verify sig via known-nodeid and MDC bytesConstRef sigBytes(_packet.cropped(h256::size, Signature::size)); Public nodeid(dev::recover(*(Signature const*)sigBytes.data(), sha3(signedBytes))); if (!nodeid) { clog(NodeTableTriviaSummary) << "Invalid message signature from " << _from.address().to_string() << ":" << _from.port(); return; } unsigned packetType = signedBytes[0]; bytesConstRef rlpBytes(_packet.cropped(h256::size + Signature::size + 1)); try { RLP rlp(rlpBytes); switch (packetType) { case Pong::type: { Pong in = Pong::fromBytesConstRef(_from, rlpBytes); // whenever a pong is received, check if it's in m_evictions bool found = false; EvictionTimeout evictionEntry; DEV_GUARDED(x_evictions) for (auto it = m_evictions.begin(); it != m_evictions.end(); ++it) if (it->first.first == nodeid && it->first.second > std::chrono::steady_clock::now()) { found = true; evictionEntry = *it; m_evictions.erase(it); break; } if (found) { if (auto n = nodeEntry(evictionEntry.second)) dropNode(n); if (auto n = nodeEntry(evictionEntry.first.first)) n->pending = false; } else { // if not, check if it's known/pending or a pubk discovery ping if (auto n = nodeEntry(nodeid)) n->pending = false; else { DEV_GUARDED(x_pubkDiscoverPings) { if (!m_pubkDiscoverPings.count(_from.address())) return; // unsolicited pong; don't note node as active m_pubkDiscoverPings.erase(_from.address()); } if (!haveNode(nodeid)) addNode(Node(nodeid, NodeIPEndpoint(_from.address(), _from.port(), _from.port()))); } } // update our endpoint address and UDP port DEV_GUARDED(x_nodes) { if ((!m_node.endpoint || !m_node.endpoint.isAllowed()) && isPublicAddress(in.destination.address)) m_node.endpoint.address = in.destination.address; m_node.endpoint.udpPort = in.destination.udpPort; } clog(NodeTableConnect) << "PONG from " << nodeid << _from; break; } case Neighbours::type: { bool expected = false; auto now = chrono::steady_clock::now(); DEV_GUARDED(x_findNodeTimeout) m_findNodeTimeout.remove_if([&](NodeIdTimePoint const& t) { if (t.first == nodeid && now - t.second < c_reqTimeout) expected = true; else if (t.first == nodeid) return true; return false; }); if (!expected) { clog(NetConnect) << "Dropping unsolicited neighbours packet from " << _from.address(); break; } Neighbours in = Neighbours::fromBytesConstRef(_from, rlpBytes); for (auto n: in.neighbours) addNode(Node(n.node, n.endpoint)); break; } case FindNode::type: { FindNode in = FindNode::fromBytesConstRef(_from, rlpBytes); if (RLPXDatagramFace::secondsSinceEpoch() > in.ts) { clog(NodeTableTriviaSummary) << "Received expired FindNode from " << _from.address().to_string() << ":" << _from.port(); return; } vector<shared_ptr<NodeEntry>> nearest = nearestNodeEntries(in.target); static unsigned const nlimit = (m_socketPointer->maxDatagramSize - 109) / 90; for (unsigned offset = 0; offset < nearest.size(); offset += nlimit) { Neighbours out(_from, nearest, offset, nlimit); out.sign(m_secret); if (out.data.size() > 1280) clog(NetWarn) << "Sending truncated datagram, size: " << out.data.size(); m_socketPointer->send(out); } break; } case PingNode::type: { PingNode in = PingNode::fromBytesConstRef(_from, rlpBytes); if (in.version < dev::p2p::c_protocolVersion) { if (in.version == 3) { compat::Pong p(in.source); p.echo = sha3(rlpBytes); p.sign(m_secret); m_socketPointer->send(p); } else return; } if (RLPXDatagramFace::secondsSinceEpoch() > in.ts) { clog(NodeTableTriviaSummary) << "Received expired PingNode from " << _from.address().to_string() << ":" << _from.port(); return; } in.source.address = _from.address(); in.source.udpPort = _from.port(); addNode(Node(nodeid, in.source)); Pong p(in.source); p.echo = sha3(rlpBytes); p.sign(m_secret); m_socketPointer->send(p); break; } default: clog(NodeTableWarn) << "Invalid message, " << hex << packetType << ", received from " << _from.address().to_string() << ":" << dec << _from.port(); return; } noteActiveNode(nodeid, _from); } catch (...) { clog(NodeTableWarn) << "Exception processing message from " << _from.address().to_string() << ":" << _from.port(); } }