ptr<MinerBlock> GetBlockTemplate(const vector<String>& capabilities) override { VarValue caps; for (int i=0; i<capabilities.size(); ++i) caps.Set(i, capabilities[i]); VarValue par; par.Set("capabilities", caps); VarValue jr = Call("getblocktemplate", par); return MinerBlock::FromJson(jr); }
SinceBlockInfo ListSinceBlock(const HashValue& hashBlock) override { SinceBlockInfo r; VarValue v = !hashBlock ? Call("listsinceblock") : Call("listsinceblock", EXT_STR(hashBlock)); r.LastBlock = HashValue(v["lastblock"].ToString()); VarValue vtx = v["transactions"]; r.Txes.resize(vtx.size()); for (int i=0; i<r.Txes.size(); ++i) r.Txes[i] = ToTxInfo(vtx[i]); return r; }
bool VarValue::operator==(const VarValue& v) const { if (type() != v.type()) return false; switch (type()) { case VarType::Null: return true; case VarType::Bool: return ToBool() == v.ToBool(); case VarType::Int: return ToInt64() == v.ToInt64(); case VarType::Float: return ToDouble() == v.ToDouble(); case VarType::String: return ToString() == v.ToString(); case VarType::Array: if (size() != v.size()) return false; for (int i=0; i<size(); ++i) if (_self[i] != v[i]) return false; return true; case VarType::Map: { if (size() != v.size()) return false; vector<String> keys = Keys(); for (int i=0; i<keys.size(); ++i) { const String& key = keys[i]; if (!v.HasKey(key) || _self[key] != v[key]) return false; } return true; } default: Throw(E_NOTIMPL); } }
void ProcessSubmitResult(const VarValue& v) { switch (v.type()) { case VarType::Null: break; case VarType::String: { String rej = v.ToString(); throw system_error(SubmitRejectionCode(rej), coin_category(), rej); } case VarType::Map: throw system_error(SubmitRejectionCode("rejected"), coin_category(), String::Join(", ", v.Keys())); default: Throw(errc::invalid_argument); } }
TxInfo ToTxInfo(const VarValue& v) { TxInfo r; if (VarValue vAddress = v["address"]) r.Address = vAddress.ToString(); r.HashTx = HashValue(v["txid"].ToString()); r.Confirmations = int32_t(v["confirmations"].ToInt64()); r.Timestamp = DateTime::from_time_t(v["time"].ToInt64()); if (r.Confirmations) { r.HashBlock = HashValue(v["blockhash"].ToString()); } r.Amount = AmountToDecimal(v["amount"]); r.Generated = v.HasKey("generated") && v["generated"].ToBool(); if (VarValue vDetails = v["details"]) { for (size_t i=0; i<vDetails.size(); ++i) { VarValue vd = vDetails[i]; TxInfo::TxDetails d; d.Account = vd["account"].ToString(); d.Address = vd["address"].ToString(); d.IsSend = vd["category"].ToString() == "send"; d.Amount = AmountToDecimal(vd["amount"]); r.Details.push_back(d); } } return r; }
size_t hash_value(const VarValue& v) { switch (v.type()) { case VarType::Null: return 0; case VarType::Int: return hash<Int64>()(v.ToInt64()); case VarType::Float: return hash<double>()(v.ToDouble()); case VarType::Bool: return hash<bool>()(v.ToBool()); case VarType::String: return hash<String>()(v.ToString()); case VarType::Array: { size_t r = 0; for (int i=0; i<v.size(); ++i) r += hash<VarValue>()(v[i]); return r; } case VarType::Map: { vector<String> keys = v.Keys(); size_t r = 0; for (int i=0; i<keys.size(); ++i) r += hash<VarValue>()(v[keys[i]]); return r; } default: Throw(E_NOTIMPL); } }
BlockInfo GetBlock(const HashValue& hashBlock) override { BlockInfo r; VarValue v = Call("getblock", EXT_STR(hashBlock)); r.Version = (int32_t)v["version"].ToInt64(); r.Timestamp = DateTime::from_time_t(v["time"].ToInt64()); r.Hash = HashValue(v["hash"].ToString()); if (VarValue vpbh = v["previousblockhash"]) r.PrevBlockHash = HashValue(vpbh.ToString()); r.MerkleRoot = HashValue(v["merkleroot"].ToString()); r.Height = (int)v["height"].ToInt64(); r.Confirmations = (int)v["confirmations"].ToInt64(); r.Difficulty = v["difficulty"].ToDouble(); VarValue vtx = v["tx"]; r.HashTxes.resize(vtx.size()); for (size_t i=0; i<r.HashTxes.size(); ++i) r.HashTxes[i] = HashValue(vtx[i].ToString()); return r; }
void SubmitBlock(const ConstBuf& data, RCString workid) override { String sdata = EXT_STR(data); if (HasSubmitBlockMethod) { try { DBG_LOCAL_IGNORE_CONDITION(ExtErr::JSON_RPC_MethodNotFound); VarValue par; if (!workid.empty()) par.Set("workid", workid); ProcessSubmitResult(Call("submitblock", sdata, par)); return; } catch (const system_error& ex) { if (ex.code() != json_rpc_errc::MethodNotFound) { TRC(1, ex.what()); throw; } HasSubmitBlockMethod = false; } } if (!HasSubmitBlockMethod) { VarValue par; par.Set("data", sdata); ProcessSubmitResult(Call("getblocktemplate", par)); } }
decimal64 AmountToDecimal(const VarValue& v) { return make_decimal64(int64_t(v.ToDouble() * 100000000), -8); //!!! not precise; }