boost::optional<PublicKey> parseBase58 (TokenType type, std::string const& s) { auto const result = decodeBase58Token(s, type); auto const pks = makeSlice(result); if (!publicKeyType(pks)) return boost::none; return PublicKey(pks); }
boost::optional<PublicKey> parseBase58 (TokenType type, std::string const& s) { auto const result = decodeBase58Token(s, type); if (result.empty()) return boost::none; if (result.size() != 33) return boost::none; return PublicKey(makeSlice(result)); }
PublicKey PublicKey::fromPEMFile(const QString &fileName, ConvertResult *result, const QString &provider) { QString pem; if(!stringFromFile(fileName, &pem)) { if(result) *result = ErrorFile; return PublicKey(); } return fromPEM(pem, result, provider); }
boost::optional<Manifest> Manifest::make_Manifest (std::string s) { try { STObject st (sfGeneric); SerialIter sit (s.data (), s.size ()); st.set (sit); auto const pk = st.getFieldVL (sfPublicKey); if (! publicKeyType (makeSlice(pk))) return boost::none; auto const opt_seq = get (st, sfSequence); auto const opt_msig = get (st, sfMasterSignature); if (!opt_seq || !opt_msig) return boost::none; // Signing key and signature are not required for // master key revocations if (*opt_seq != std::numeric_limits<std::uint32_t>::max ()) { auto const spk = st.getFieldVL (sfSigningPubKey); if (! publicKeyType (makeSlice(spk))) return boost::none; auto const opt_sig = get (st, sfSignature); if (! opt_sig) return boost::none; return Manifest (std::move (s), PublicKey (makeSlice(pk)), PublicKey (makeSlice(spk)), *opt_seq); } return Manifest (std::move (s), PublicKey (makeSlice(pk)), PublicKey(), *opt_seq); } catch (std::exception const&) { return boost::none; } }
QCA::PGPKey GlooxAccount::GetEntryKey (QObject *entryObj) const { ICLEntry *entry = qobject_cast<ICLEntry*> (entryObj); if (!entry) { qWarning () << Q_FUNC_INFO << entryObj << "doesn't implement ICLEntry"; return QCA::PGPKey (); } auto mgr = ClientConnection_->GetCryptHandler ()->GetPGPManager (); return mgr->PublicKey (entry->GetHumanReadableID ()); }
STValidation::STValidation (SerialIter& sit, bool checkSignature) : STObject (getFormat (), sit, sfValidation) { mNodeID = calcNodeID( PublicKey(makeSlice (getFieldVL (sfSigningPubKey)))); assert (mNodeID.isNonZero ()); if (checkSignature && !isValid ()) { JLOG (debugLog().error()) << "Invalid validation" << getJson (0); Throw<std::runtime_error> ("Invalid validation"); } }
NotTEC Transactor::checkSingleSign (PreclaimContext const& ctx) { auto const id = ctx.tx.getAccountID(sfAccount); auto const sle = ctx.view.read( keylet::account(id)); auto const hasAuthKey = sle->isFieldPresent (sfRegularKey); // Consistency: Check signature & verify the transaction's signing // public key is authorized for signing. auto const spk = ctx.tx.getSigningPubKey(); if (!publicKeyType (makeSlice (spk))) { JLOG(ctx.j.trace()) << "checkSingleSign: signing public key type is unknown"; return tefBAD_AUTH; // FIXME: should be better error! } auto const pkAccount = calcAccountID ( PublicKey (makeSlice (spk))); if (pkAccount == id) { // Authorized to continue. if (sle->isFlag(lsfDisableMaster)) return tefMASTER_DISABLED; } else if (hasAuthKey && (pkAccount == sle->getAccountID (sfRegularKey))) { // Authorized to continue. } else if (hasAuthKey) { JLOG(ctx.j.trace()) << "checkSingleSign: Not authorized to use account."; return tefBAD_AUTH; } else { JLOG(ctx.j.trace()) << "checkSingleSign: Not authorized to use account."; return tefBAD_AUTH_MASTER; } return tesSUCCESS; }
IPTransportInfo::IPTransportInfo(ITransportConnectionInfoPtr connectionInfo) : GenericTransportInfo(connectionInfo->getServerType(), ProtocolMetaData()) { if (!connectionInfo || connectionInfo->getConnectionInfo().empty()) { KAA_LOG_ERROR("Failed to create IP transport data: bad input data"); throw KaaException("Bad connection data"); } serverType_ = connectionInfo->getServerType(); connectionData_ = connectionInfo->getConnectionInfo(); accessPointId_ = connectionInfo->getAccessPointId(); protocolId_ = connectionInfo->getTransportId(); std::uint8_t *data = connectionData_.data(); std::int32_t publicKeyLength = boost::asio::detail::socket_ops::network_to_host_long(*((int32_t *)data)); data += sizeof(std::int32_t); publicKey_ = PublicKey(data, publicKeyLength); data += publicKeyLength; std::int32_t hostLength = boost::asio::detail::socket_ops::network_to_host_long(*((int32_t *)data)); data += sizeof(std::int32_t); host_.assign(data, data + hostLength); data += hostLength; port_ = boost::asio::detail::socket_ops::network_to_host_long(*((int32_t *)data)); std::ostringstream ss; ss << "http://" << host_ << ":" << port_; url_.assign(ss.str()); if ((3 * sizeof(std::int32_t) + publicKeyLength + hostLength) > connectionData_.size()) { KAA_LOG_ERROR("Failed to create IP transport data: less size of input data than needed"); throw KaaException("Bad connection data"); } KAA_LOG_TRACE(boost::format("Create IP transport data: host=%1%, port=%2%, publicKeyLength=%3%") % host_% port_ % publicKey_.size()); }
bool PgpManager::handleStanza (const QDomElement& stanza) { const auto& tagName = stanza.tagName (); if ("message" != tagName && "presence" != tagName) return false; const auto& from = stanza.attribute ("from"); // Case 1: signed presence|message const auto& x_element = stanza.firstChildElement ("x"); if (x_element.namespaceURI () == NsSigned) { const auto& status = stanza.firstChildElement ("status"); const auto& message = status.text (); const auto& signature = x_element.text (); const QCA::PGPKey key = PublicKey (from); if (!IsValidSignature (key, message.toUtf8 (), signature.toLatin1 ())) emit invalidSignatureReceived (from); else if (tagName == "message") emit signedMessageReceived (from); else if (tagName == "presence") emit signedPresenceReceived (from); } // Case 2: encrypted message if (x_element.namespaceURI () == NsEncrypted) { const auto& encryptedBodyStr = x_element.text (); const auto& encryptedBody = encryptedBodyStr.toLatin1 (); const auto& decryptedBody = DecryptBody (encryptedBody); if (!decryptedBody.isEmpty ()) emit encryptedMessageReceived (from, QString::fromUtf8 (decryptedBody)); } return false; }
std::uint64_t SetRegularKey::calculateBaseFee ( PreclaimContext const& ctx) { auto const id = ctx.tx.getAccountID(sfAccount); auto const spk = ctx.tx.getSigningPubKey(); if (publicKeyType (makeSlice (spk))) { if (calcAccountID(PublicKey (makeSlice(spk))) == id) { auto const sle = ctx.view.read(keylet::account(id)); if (sle && (! (sle->getFlags () & lsfPasswordSpent))) { // flag is armed and they signed with the right account return 0; } } } return Transactor::calculateBaseFee (ctx); }
std::pair<bool, std::string> STTx::checkSingleSign () const { // We don't allow both a non-empty sfSigningPubKey and an sfSigners. // That would allow the transaction to be signed two ways. So if both // fields are present the signature is invalid. if (isFieldPresent (sfSigners)) return {false, "Cannot both single- and multi-sign."}; bool validSig = false; try { bool const fullyCanonical = (getFlags() & tfFullyCanonicalSig); auto const spk = getFieldVL (sfSigningPubKey); if (publicKeyType (makeSlice(spk))) { Blob const signature = getFieldVL (sfTxnSignature); Blob const data = getSigningData (*this); validSig = verify ( PublicKey (makeSlice(spk)), makeSlice(data), makeSlice(signature), fullyCanonical); } } catch (std::exception const&) { // Assume it was a signature failure. validSig = false; } if (validSig == false) return {false, "Invalid signature."}; return {true, ""}; }
int wmain( _In_ int argc, _In_ wchar_t* argv[]) { #elif (defined(PLATFORM_LINUX) || defined(PLATFORM_MACX)) int main(int argc, char *argv[]) { #endif #if defined(ENABLE_LIBSODIUM) //Libsodium initialization if (sodium_init() != EXIT_SUCCESS) { wprintf_s(L"Libsodium initialization error\n"); #if defined(PLATFORM_WIN) system("Pause"); #endif return EXIT_FAILURE; } FILE *Output = nullptr; //Output. #if defined(PLATFORM_WIN) _wfopen_s(&Output, L"KeyPair.txt", L"w+,ccs=UTF-8"); #elif (defined(PLATFORM_LINUX) || defined(PLATFORM_MACX)) Output = fopen("KeyPair.txt", "w+"); #endif if (Output != nullptr) { //Initialization and make keypair. size_t Index = 0; std::shared_ptr<char> Buffer(new char[KEYPAIR_MESSAGE_LEN]()); std::shared_ptr<uint8_t> PublicKey(new uint8_t[crypto_box_PUBLICKEYBYTES]()), SecretKey(new uint8_t[crypto_box_SECRETKEYBYTES]()); memset(Buffer.get(), 0, KEYPAIR_MESSAGE_LEN); memset(PublicKey.get(), 0, crypto_box_PUBLICKEYBYTES); memset(SecretKey.get(), 0, crypto_box_SECRETKEYBYTES); crypto_box_keypair(PublicKey.get(), SecretKey.get()); //Write public key. memset(Buffer.get(), 0, KEYPAIR_MESSAGE_LEN); if (sodium_bin2hex(Buffer.get(), KEYPAIR_MESSAGE_LEN, PublicKey.get(), crypto_box_PUBLICKEYBYTES) == nullptr) wprintf_s(L"Create ramdom key pair failed, please try again.\n"); CaseConvert(true, Buffer.get(), KEYPAIR_MESSAGE_LEN); fwprintf_s(Output, L"Client Public Key = "); for (Index = 0;Index < strnlen_s(Buffer.get(), KEYPAIR_MESSAGE_LEN);++Index) { if (Index > 0 && Index % KEYPAIR_INTERVAL == 0 && Index + 1U < strnlen_s(Buffer.get(), KEYPAIR_MESSAGE_LEN)) fwprintf_s(Output, L":"); fwprintf_s(Output, L"%c", Buffer.get()[Index]); } memset(Buffer.get(), 0, KEYPAIR_MESSAGE_LEN); fwprintf_s(Output, L"\n"); //Write secret key. if (sodium_bin2hex(Buffer.get(), KEYPAIR_MESSAGE_LEN, SecretKey.get(), crypto_box_SECRETKEYBYTES) == nullptr) wprintf_s(L"Create ramdom key pair failed, please try again.\n"); CaseConvert(true, Buffer.get(), KEYPAIR_MESSAGE_LEN); fwprintf_s(Output, L"Client Secret Key = "); for (Index = 0;Index < strnlen_s(Buffer.get(), KEYPAIR_MESSAGE_LEN);++Index) { if (Index > 0 && Index % KEYPAIR_INTERVAL == 0 && Index + 1U < strnlen_s(Buffer.get(), KEYPAIR_MESSAGE_LEN)) fwprintf_s(Output, L":"); fwprintf_s(Output, L"%c", Buffer.get()[Index]); } fwprintf_s(Output, L"\n"); //Close file. fclose(Output); } else { wprintf_s(L"Cannot create target file(KeyPair.txt)\n"); #if defined(PLATFORM_WIN) system("Pause"); #endif return EXIT_FAILURE; } wprintf_s(L"Create ramdom key pair success, please check KeyPair.txt.\n\n"); #if defined(PLATFORM_WIN) system("Pause"); #endif #else #if defined(PLATFORM_WIN) wprintf_s(L"LibSodium is disable.\n\n"); system("Pause"); #elif (defined(PLATFORM_LINUX) || defined(PLATFORM_MACX)) wprintf(L"LibSodium is disable.\n\n"); #endif #endif return EXIT_SUCCESS; } //Convert lowercase/uppercase words to uppercase/lowercase words(Character version) #if defined(ENABLE_LIBSODIUM) void __fastcall CaseConvert( _In_ const bool IsLowerToUpper, _Inout_ char *Buffer, _In_ const size_t Length) { for (size_t Index = 0;Index < Length;++Index) { //Lowercase to uppercase if (IsLowerToUpper) Buffer[Index] = (char)toupper(Buffer[Index]); //Uppercase to lowercase else Buffer[Index] = (char)tolower(Buffer[Index]); } return; }
PublicKey getPublicKey() const { return PublicKey(encryptExponent, modulus); }
void ServerConfiguration::createTemplateConfigurationFile(QString const& filename) { ServerConfiguration sc("localhost", 12345, PublicKey(), "https://localhost/identity/%1", "OpenMittsu/1.0A", "", "https://localhost/%1", "https://localhost/%1/done", "https://localhost/upload", "OpenMittsu/1.0A", ""); sc.toFile(filename); }
NotTEC Transactor::checkMultiSign (PreclaimContext const& ctx) { auto const id = ctx.tx.getAccountID(sfAccount); // Get mTxnAccountID's SignerList and Quorum. std::shared_ptr<STLedgerEntry const> sleAccountSigners = ctx.view.read (keylet::signers(id)); // If the signer list doesn't exist the account is not multi-signing. if (!sleAccountSigners) { JLOG(ctx.j.trace()) << "applyTransaction: Invalid: Not a multi-signing account."; return tefNOT_MULTI_SIGNING; } // We have plans to support multiple SignerLists in the future. The // presence and defaulted value of the SignerListID field will enable that. assert (sleAccountSigners->isFieldPresent (sfSignerListID)); assert (sleAccountSigners->getFieldU32 (sfSignerListID) == 0); auto accountSigners = SignerEntries::deserialize (*sleAccountSigners, ctx.j, "ledger"); if (accountSigners.second != tesSUCCESS) return accountSigners.second; // Get the array of transaction signers. STArray const& txSigners (ctx.tx.getFieldArray (sfSigners)); // Walk the accountSigners performing a variety of checks and see if // the quorum is met. // Both the multiSigners and accountSigners are sorted by account. So // matching multi-signers to account signers should be a simple // linear walk. *All* signers must be valid or the transaction fails. std::uint32_t weightSum = 0; auto iter = accountSigners.first.begin (); for (auto const& txSigner : txSigners) { AccountID const txSignerAcctID = txSigner.getAccountID (sfAccount); // Attempt to match the SignerEntry with a Signer; while (iter->account < txSignerAcctID) { if (++iter == accountSigners.first.end ()) { JLOG(ctx.j.trace()) << "applyTransaction: Invalid SigningAccount.Account."; return tefBAD_SIGNATURE; } } if (iter->account != txSignerAcctID) { // The SigningAccount is not in the SignerEntries. JLOG(ctx.j.trace()) << "applyTransaction: Invalid SigningAccount.Account."; return tefBAD_SIGNATURE; } // We found the SigningAccount in the list of valid signers. Now we // need to compute the accountID that is associated with the signer's // public key. auto const spk = txSigner.getFieldVL (sfSigningPubKey); if (!publicKeyType (makeSlice(spk))) { JLOG(ctx.j.trace()) << "checkMultiSign: signing public key type is unknown"; return tefBAD_SIGNATURE; } AccountID const signingAcctIDFromPubKey = calcAccountID(PublicKey (makeSlice(spk))); // Verify that the signingAcctID and the signingAcctIDFromPubKey // belong together. Here is are the rules: // // 1. "Phantom account": an account that is not in the ledger // A. If signingAcctID == signingAcctIDFromPubKey and the // signingAcctID is not in the ledger then we have a phantom // account. // B. Phantom accounts are always allowed as multi-signers. // // 2. "Master Key" // A. signingAcctID == signingAcctIDFromPubKey, and signingAcctID // is in the ledger. // B. If the signingAcctID in the ledger does not have the // asfDisableMaster flag set, then the signature is allowed. // // 3. "Regular Key" // A. signingAcctID != signingAcctIDFromPubKey, and signingAcctID // is in the ledger. // B. If signingAcctIDFromPubKey == signingAcctID.RegularKey (from // ledger) then the signature is allowed. // // No other signatures are allowed. (January 2015) // In any of these cases we need to know whether the account is in // the ledger. Determine that now. auto sleTxSignerRoot = ctx.view.read (keylet::account(txSignerAcctID)); if (signingAcctIDFromPubKey == txSignerAcctID) { // Either Phantom or Master. Phantoms automatically pass. if (sleTxSignerRoot) { // Master Key. Account may not have asfDisableMaster set. std::uint32_t const signerAccountFlags = sleTxSignerRoot->getFieldU32 (sfFlags); if (signerAccountFlags & lsfDisableMaster) { JLOG(ctx.j.trace()) << "applyTransaction: Signer:Account lsfDisableMaster."; return tefMASTER_DISABLED; } } } else { // May be a Regular Key. Let's find out. // Public key must hash to the account's regular key. if (!sleTxSignerRoot) { JLOG(ctx.j.trace()) << "applyTransaction: Non-phantom signer lacks account root."; return tefBAD_SIGNATURE; } if (!sleTxSignerRoot->isFieldPresent (sfRegularKey)) { JLOG(ctx.j.trace()) << "applyTransaction: Account lacks RegularKey."; return tefBAD_SIGNATURE; } if (signingAcctIDFromPubKey != sleTxSignerRoot->getAccountID (sfRegularKey)) { JLOG(ctx.j.trace()) << "applyTransaction: Account doesn't match RegularKey."; return tefBAD_SIGNATURE; } } // The signer is legitimate. Add their weight toward the quorum. weightSum += iter->weight; } // Cannot perform transaction if quorum is not met. if (weightSum < sleAccountSigners->getFieldU32 (sfSignerQuorum)) { JLOG(ctx.j.trace()) << "applyTransaction: Signers failed to meet quorum."; return tefBAD_QUORUM; } // Met the quorum. Continue. return tesSUCCESS; }
PublicKey STValidation::getSignerPublic () const { return PublicKey(makeSlice (getFieldVL (sfSigningPubKey))); }
ListDisposition ValidatorList::applyList ( std::string const& manifest, std::string const& blob, std::string const& signature, std::uint32_t version) { if (version != requiredListVersion) return ListDisposition::unsupported_version; boost::unique_lock<boost::shared_mutex> lock{mutex_}; Json::Value list; PublicKey pubKey; auto const result = verify (list, pubKey, manifest, blob, signature); if (result != ListDisposition::accepted) return result; // Update publisher's list Json::Value const& newList = list["validators"]; publisherLists_[pubKey].available = true; publisherLists_[pubKey].sequence = list["sequence"].asUInt (); publisherLists_[pubKey].expiration = TimeKeeper::time_point{ TimeKeeper::duration{list["expiration"].asUInt()}}; std::vector<PublicKey>& publisherList = publisherLists_[pubKey].list; std::vector<PublicKey> oldList = publisherList; publisherList.clear (); publisherList.reserve (newList.size ()); std::vector<std::string> manifests; for (auto const& val : newList) { if (val.isObject () && val.isMember ("validation_public_key") && val["validation_public_key"].isString ()) { std::pair<Blob, bool> ret (strUnHex ( val["validation_public_key"].asString ())); if (! ret.second || ! ret.first.size ()) { JLOG (j_.error()) << "Invalid node identity: " << val["validation_public_key"].asString (); } else { publisherList.push_back ( PublicKey(Slice{ ret.first.data (), ret.first.size() })); } if (val.isMember ("manifest") && val["manifest"].isString ()) manifests.push_back(val["manifest"].asString ()); } } // Update keyListings_ for added and removed keys std::sort ( publisherList.begin (), publisherList.end ()); auto iNew = publisherList.begin (); auto iOld = oldList.begin (); while (iNew != publisherList.end () || iOld != oldList.end ()) { if (iOld == oldList.end () || (iNew != publisherList.end () && *iNew < *iOld)) { // Increment list count for added keys ++keyListings_[*iNew]; ++iNew; } else if (iNew == publisherList.end () || (iOld != oldList.end () && *iOld < *iNew)) { // Decrement list count for removed keys if (keyListings_[*iOld] <= 1) keyListings_.erase (*iOld); else --keyListings_[*iOld]; ++iOld; } else { ++iNew; ++iOld; } } if (publisherList.empty()) { JLOG (j_.warn()) << "No validator keys included in valid list"; } for (auto const& valManifest : manifests) { auto m = Manifest::make_Manifest ( beast::detail::base64_decode(valManifest)); if (! m || ! keyListings_.count (m->masterKey)) { JLOG (j_.warn()) << "List for " << strHex(pubKey) << " contained untrusted validator manifest"; continue; } auto const result = validatorManifests_.applyManifest (std::move(*m)); if (result == ManifestDisposition::invalid) { JLOG (j_.warn()) << "List for " << strHex(pubKey) << " contained invalid validator manifest"; } } return ListDisposition::accepted; }
std::pair<bool, std::string> STTx::checkMultiSign () const { // Make sure the MultiSigners are present. Otherwise they are not // attempting multi-signing and we just have a bad SigningPubKey. if (!isFieldPresent (sfSigners)) return {false, "Empty SigningPubKey."}; // We don't allow both an sfSigners and an sfTxnSignature. Both fields // being present would indicate that the transaction is signed both ways. if (isFieldPresent (sfTxnSignature)) return {false, "Cannot both single- and multi-sign."}; STArray const& signers {getFieldArray (sfSigners)}; // There are well known bounds that the number of signers must be within. if (signers.size() < minMultiSigners || signers.size() > maxMultiSigners) return {false, "Invalid Signers array size."}; // We can ease the computational load inside the loop a bit by // pre-constructing part of the data that we hash. Fill a Serializer // with the stuff that stays constant from signature to signature. Serializer const dataStart {startMultiSigningData (*this)}; // We also use the sfAccount field inside the loop. Get it once. auto const txnAccountID = getAccountID (sfAccount); // Determine whether signatures must be full canonical. bool const fullyCanonical = (getFlags() & tfFullyCanonicalSig); // Signers must be in sorted order by AccountID. AccountID lastAccountID (beast::zero); for (auto const& signer : signers) { auto const accountID = signer.getAccountID (sfAccount); // The account owner may not multisign for themselves. if (accountID == txnAccountID) return {false, "Invalid multisigner."}; // No duplicate signers allowed. if (lastAccountID == accountID) return {false, "Duplicate Signers not allowed."}; // Accounts must be in order by account ID. No duplicates allowed. if (lastAccountID > accountID) return {false, "Unsorted Signers array."}; // The next signature must be greater than this one. lastAccountID = accountID; // Verify the signature. bool validSig = false; try { Serializer s = dataStart; finishMultiSigningData (accountID, s); auto spk = signer.getFieldVL (sfSigningPubKey); if (publicKeyType (makeSlice(spk))) { Blob const signature = signer.getFieldVL (sfTxnSignature); validSig = verify ( PublicKey (makeSlice(spk)), s.slice(), makeSlice(signature), fullyCanonical); } } catch (std::exception const&) { // We assume any problem lies with the signature. validSig = false; } if (!validSig) return {false, std::string("Invalid signature on account ") + toBase58(accountID) + "."}; } // All signatures verified. return {true, ""}; }
bool ValidatorList::load ( PublicKey const& localSigningKey, std::vector<std::string> const& configKeys, std::vector<std::string> const& publisherKeys) { static boost::regex const re ( "[[:space:]]*" // skip leading whitespace "([[:alnum:]]+)" // node identity "(?:" // begin optional comment block "[[:space:]]+" // (skip all leading whitespace) "(?:" // begin optional comment "(.*[^[:space:]]+)" // the comment "[[:space:]]*" // (skip all trailing whitespace) ")?" // end optional comment ")?" // end optional comment block ); boost::unique_lock<boost::shared_mutex> read_lock{mutex_}; JLOG (j_.debug()) << "Loading configured trusted validator list publisher keys"; std::size_t count = 0; for (auto key : publisherKeys) { JLOG (j_.trace()) << "Processing '" << key << "'"; auto const ret = strUnHex (key); if (! ret.second || ! ret.first.size ()) { JLOG (j_.error()) << "Invalid validator list publisher key: " << key; return false; } auto id = PublicKey(Slice{ ret.first.data (), ret.first.size() }); if (validatorManifests_.revoked (id)) { JLOG (j_.warn()) << "Configured validator list publisher key is revoked: " << key; continue; } if (publisherLists_.count(id)) { JLOG (j_.warn()) << "Duplicate validator list publisher key: " << key; continue; } publisherLists_[id].available = false; ++count; } JLOG (j_.debug()) << "Loaded " << count << " keys"; localPubKey_ = validatorManifests_.getMasterKey (localSigningKey); // Treat local validator key as though it was listed in the config if (localPubKey_.size()) keyListings_.insert ({ localPubKey_, 1 }); JLOG (j_.debug()) << "Loading configured validator keys"; count = 0; PublicKey local; for (auto const& n : configKeys) { JLOG (j_.trace()) << "Processing '" << n << "'"; boost::smatch match; if (!boost::regex_match (n, match, re)) { JLOG (j_.error()) << "Malformed entry: '" << n << "'"; return false; } auto const id = parseBase58<PublicKey>( TokenType::TOKEN_NODE_PUBLIC, match[1]); if (!id) { JLOG (j_.error()) << "Invalid node identity: " << match[1]; return false; } // Skip local key which was already added if (*id == localPubKey_ || *id == localSigningKey) continue; auto ret = keyListings_.insert ({*id, 1}); if (! ret.second) { JLOG (j_.warn()) << "Duplicate node identity: " << match[1]; continue; } auto it = publisherLists_.emplace( std::piecewise_construct, std::forward_as_tuple(local), std::forward_as_tuple()); // Config listed keys never expire if (it.second) it.first->second.expiration = TimeKeeper::time_point::max(); it.first->second.list.emplace_back(std::move(*id)); it.first->second.available = true; ++count; } JLOG (j_.debug()) << "Loaded " << count << " entries"; return true; }