All ints in quality calculation, quality to quality string

This commit is contained in:
Mariano Sorgente
2020-02-10 18:39:03 -05:00
parent 9f9dcba021
commit 1c0f7fee49
20 changed files with 166 additions and 159 deletions
+4 -6
View File
@@ -74,11 +74,10 @@ PYBIND11_MODULE(chiapos, m) {
const uint8_t* challenge_ptr = reinterpret_cast<const uint8_t*>(challenge_str.data());
std::vector<LargeBits> qualities = dp.GetQualitiesForChallenge(challenge_ptr);
std::vector<py::bytes> ret;
uint8_t* quality_buf = new uint8_t[Util::ByteAlign(2 * dp.GetSize()) / 8];
uint8_t* quality_buf = new uint8_t[32];
for (LargeBits quality : qualities) {
quality.ToBytes(quality_buf);
py::bytes quality_py = py::bytes(reinterpret_cast<char*>(quality_buf),
Util::ByteAlign(2 * dp.GetSize()) / 8);
py::bytes quality_py = py::bytes(reinterpret_cast<char*>(quality_buf), 32);
ret.push_back(quality_py);
}
delete[] quality_buf;
@@ -113,10 +112,9 @@ PYBIND11_MODULE(chiapos, m) {
if (quality.GetSize() == 0) {
return stdx::optional<py::bytes>();
}
uint8_t* quality_buf = new uint8_t[Util::ByteAlign(2 * k) / 8];
uint8_t* quality_buf = new uint8_t[32];
quality.ToBytes(quality_buf);
py::bytes quality_py = py::bytes(reinterpret_cast<char*>(quality_buf),
Util::ByteAlign(2 * k) / 8);
py::bytes quality_py = py::bytes(reinterpret_cast<char*>(quality_buf), 32);
delete[] quality_buf;
return stdx::optional<py::bytes>(quality_py);
});
+1 -1
View File
@@ -123,7 +123,7 @@ int main(int argc, char *argv[]) {
DiskProver prover(filename);
vector<LargeBits> qualities = prover.GetQualitiesForChallenge(challenge_bytes);
for (uint32_t i = 0; i < qualities.size(); i++) {
k = qualities[i].GetSize() / 2;
k = prover.GetSize() / 2;
uint8_t proof_data[8 * k];
LargeBits proof = prover.GetFullProof(challenge_bytes, i);
proof.ToBytes(proof_data);
+9 -3
View File
@@ -29,6 +29,7 @@
#include "encoding.hpp"
#include "calculate_bucket.hpp"
#include "plotter_disk.hpp"
#include "../lib/include/picosha2.hpp"
// The DiskProver, given a correctly formatted plot file, can efficiently generate valid proofs
// of space, for a given challenge.
@@ -127,7 +128,7 @@ class DiskProver {
return k;
}
// Given a challenge, returns a quality string, which is 2 adjecent x values,
// Given a challenge, returns a quality string, which is sha256(challenge + 2 adjecent x values),
// from the 64 value proof. Note that this is more efficient than fetching all
// 64 x values, which are in different parts of the disk.
std::vector<LargeBits> GetQualitiesForChallenge(const uint8_t* challenge) {
@@ -165,8 +166,13 @@ class DiskProver {
uint128_t new_line_point = ReadLinePoint(1, position);
auto x1x2 = Encoding::LinePointToSquare(new_line_point);
// The final two x values (which are stored in the same location) are returned.
qualities.push_back(LargeBits(x1x2.second, k) + LargeBits(x1x2.first, k));
// The final two x values (which are stored in the same location) are hashed
vector<unsigned char> hash_input(32 + Util::ByteAlign(2 * k) / 8, 0);
memcpy(hash_input.data(), challenge, 32);
(LargeBits(x1x2.second, k) + LargeBits(x1x2.first, k)).ToBytes(hash_input.data() + 32);
vector<unsigned char> hash(picosha2::k_digest_size);
picosha2::hash256(hash_input.begin(), hash_input.end(), hash.begin(), hash.end());
qualities.push_back(LargeBits(hash.data(), 32, 256));
}
disk_file.clear();
disk_file.sync();
+12 -7
View File
@@ -21,10 +21,10 @@
class Verifier {
public:
// Gets the quality string from a proof in proof ordering. The quality string is two
// adjacent values, determined by the quality index (1-32), and the proof in plot
// ordering.
LargeBits GetQualityString(uint8_t k, LargeBits proof, uint16_t quality_index) {
// Gets the quality string from a proof in proof ordering. The quality string is sha256 of
// the challenge + two adjacent values, determined by the quality index (1-32),
// and the proof in plot ordering.
LargeBits GetQualityString(uint8_t k, LargeBits proof, uint16_t quality_index, const uint8_t* challenge) {
// Converts the proof from proof ordering to plot ordering
for (uint8_t table_index = 1; table_index < 7; table_index++) {
LargeBits new_proof;
@@ -40,8 +40,13 @@ class Verifier {
}
proof = new_proof;
}
// Returns two of the x values, based on the quality index
return proof.Slice(k * quality_index, k * (quality_index + 2));
// Hashes two of the x values, based on the quality index
vector<unsigned char> hash_input(32 + Util::ByteAlign(2 * k) / 8, 0);
memcpy(hash_input.data(), challenge, 32);
proof.Slice(k * quality_index, k * (quality_index + 2)).ToBytes(hash_input.data() + 32);
vector<unsigned char> hash(picosha2::k_digest_size);
picosha2::hash256(hash_input.begin(), hash_input.end(), hash.begin(), hash.end());
return LargeBits(hash.data(), 32, 256);
}
// Validates a proof of space, and returns the quality string if the proof is valid for the given
@@ -107,7 +112,7 @@ class Verifier {
// Makes sure the output is equal to the first k bits of the challenge
if (challenge_bits.Slice(0, k) == ys[0].Slice(0, k)) {
// Returns quality string, which requires changing proof to plot ordering
return GetQualityString(k, proof_bits, quality_index);
return GetQualityString(k, proof_bits, quality_index, challenge);
} else {
return LargeBits();
}
+1 -1
View File
@@ -343,7 +343,7 @@ void TestProofOfSpace(std::string filename, uint32_t iterations, uint8_t k, uint
proof.ToBytes(proof_data);
LargeBits quality = verifier.ValidateProof(plot_id, k, hash.data(), proof_data, k*8);
REQUIRE(quality.GetSize() == 2 * k);
REQUIRE(quality.GetSize() == 256);
REQUIRE(quality == qualities[index]);
success += 1;
+3 -3
View File
@@ -50,15 +50,15 @@ def main():
try:
for i in range(args.num):
challenge = sha256(i.to_bytes(32, "big")).digest()
for index, quality in enumerate(
for index, quality_str in enumerate(
pr.get_qualities_for_challenge(challenge)
):
proof = pr.get_full_proof(challenge, index)
total_proofs += 1
ver_quality = v.validate_proof(
ver_quality_str = v.validate_proof(
plot_seed, pr.get_size(), challenge, proof
)
assert quality == ver_quality
assert quality_str == ver_quality_str
except BaseException as e:
print(
f"{type(e)}: {e} error in proving/verifying for plot {plot_filename}"
+18 -16
View File
@@ -485,7 +485,7 @@ class Blockchain:
self,
block: FullBlock,
pre_validated: bool = False,
pos_quality: bytes32 = None,
pos_quality_string: bytes32 = None,
) -> Tuple[ReceiveBlockResult, Optional[Header]]:
"""
Adds a new block into the blockchain, if it's valid and connected to the current
@@ -499,7 +499,9 @@ class Blockchain:
if block.prev_header_hash not in self.headers and not genesis:
return ReceiveBlockResult.DISCONNECTED_BLOCK, None
if not await self.validate_block(block, genesis, pre_validated, pos_quality):
if not await self.validate_block(
block, genesis, pre_validated, pos_quality_string
):
return ReceiveBlockResult.INVALID_BLOCK, None
# Cache header in memory
@@ -518,7 +520,7 @@ class Blockchain:
block: FullBlock,
prev_full_block: Optional[FullBlock],
pre_validated: bool = True,
pos_quality: bytes32 = None,
pos_quality_string: bytes32 = None,
) -> bool:
"""
Block validation algorithm. Returns true if the candidate block is fully valid
@@ -535,7 +537,7 @@ class Blockchain:
return False
# 3. Check coinbase signature with pool pk
pair = block.body.coinbase_signature.AGGSIGPair(
pair = block.body.coinbase_signature.PkMessagePair(
block.proof_of_space.pool_pubkey, block.body.coinbase.name(),
)
@@ -600,9 +602,9 @@ class Blockchain:
return False
# 10. Check proof of space based on challenge
if pos_quality is None:
pos_quality = block.proof_of_space.verify_and_get_quality()
if not pos_quality:
if pos_quality_string is None:
pos_quality_string = block.proof_of_space.verify_and_get_quality_string()
if not pos_quality_string:
return False
# 11. Check block height = prev height + 1
@@ -620,7 +622,7 @@ class Blockchain:
block: FullBlock,
genesis: bool = False,
pre_validated: bool = False,
pos_quality: bytes32 = None,
pos_quality_string: bytes32 = None,
) -> bool:
"""
Block validation algorithm. Returns true iff the candidate block is fully valid,
@@ -636,7 +638,7 @@ class Blockchain:
# 1. Validate unfinished block (check the rest of the conditions)
if not (
await self.validate_unfinished_block(
block, prev_full_block, pre_validated, pos_quality
block, prev_full_block, pre_validated, pos_quality_string
)
):
return False
@@ -652,14 +654,14 @@ class Blockchain:
ips = uint64(self.constants["VDF_IPS_STARTING"])
# 3. Check number of iterations on PoT is correct, based on prev block and PoS
if pos_quality is None:
pos_quality = block.proof_of_space.verify_and_get_quality()
if pos_quality_string is None:
pos_quality_string = block.proof_of_space.verify_and_get_quality_string()
if pos_quality is None:
if pos_quality_string is None:
return False
number_of_iters: uint64 = calculate_iterations_quality(
pos_quality,
pos_quality_string,
block.proof_of_space.size,
difficulty,
ips,
@@ -788,12 +790,12 @@ class Blockchain:
return False, None
# 10. Check proof of space based on challenge
pos_quality = block.proof_of_space.verify_and_get_quality()
pos_quality_string = block.proof_of_space.verify_and_get_quality_string()
if not pos_quality:
if not pos_quality_string:
return False, None
return True, bytes(pos_quality)
return True, bytes(pos_quality_string)
def _reconsider_heights(self, old_lca: Optional[Header], new_lca: Header):
"""
File diff suppressed because one or more lines are too long
+42
View File
@@ -0,0 +1,42 @@
from src.util.ints import uint8, uint64
from src.types.sized_bytes import bytes32
def _expected_plot_size(k: uint8) -> uint64:
"""
Given the plot size parameter k (which is between 30 and 59), computes the
expected size of the plot in bytes. This is based on efficient encoding
of the plot, and aims to be scale agnostic, so larger plots don't
necessarily get more rewards per byte.
"""
# The following line is the formula for total number of bytes. Instead we can use a formula
# for number of kilobytes, to reduce decimal usage.
# return 0.762 * k * pow(2, k)
return 780 * k * pow(2, k - 10)
def quality_str_to_quality(quality_str: bytes32, k: uint8) -> uint64:
"""
Takes a 256 bit quality, converts it to an integer between 0 and 2**256,
representing a decimal d=0.xxxxx..., where x are the bits of the quality.
Then we perform -log(d), using a Pade approximation for log:
log(1+x) = x(6+x)/(6+4x)
This is a very good approximation for x when x is close to 1. However, we only
work with big ints, to avoid using decimals. Finally, we divide by the plot size,
to make bigger plots have a proportionally
"""
t = pow(2, 256)
# xt is (dec(quality_str) - 1) * 2^256. That is, the 0.xxxxx representation of the hash,
# minus 1 (so that we can input it into the approximation for log(1+x)), times 2^256, since
# we want to work with big ints and not decimals
xt = int.from_bytes(quality_str, "big") - t
numerator = xt * xt + 6 * (xt) * t
denominator = 6 * t + 4 * (xt)
# To get the output of log(x), you would do the following
# log(1+x) = - (numerator / denominator / pow(2, 256)
# Instead, here we rearrange the terms to only have one division, which we can use bigints for
return -(pow(2, 256) * _expected_plot_size(k) * denominator) // numerator
+8 -44
View File
@@ -1,39 +1,7 @@
from decimal import ROUND_UP, Decimal, getcontext
from src.types.proof_of_space import ProofOfSpace
from src.types.sized_bytes import bytes32
from src.util.ints import uint8, uint64
# Sets a high precision so we can convert a 256 bit has to a decimal, and
# divide by a large number, while not losing any bits of precision.
getcontext().prec = 600
def _expected_plot_size(k: uint8) -> Decimal:
"""
Given the plot size parameter k (which is between 30 and 59), computes the
expected size of the plot in bytes. This is based on efficient encoding
of the plot, and aims to be scale agnostic, so larger plots don't
necessarily get more rewards per byte.
"""
return Decimal(Decimal(0.762) * k * pow(2, k))
def _quality_to_decimal(quality: bytes32) -> Decimal:
"""
Takes a 256 bit quality, converts it to an integer between 0 and 2**256,
representing a decimal d=0.xxxxx..., where x are the bits of the quality.
Then we perform -log(d), using a Pade approximation for log:
log(1+x) = x(6+x)/(6+4x)
This is a very good approximation for x when x is close to 1. However, we only
work with big ints, to avoid using decimals.
"""
t = pow(2, 256)
xt = int.from_bytes(quality, "big") - t
numerator = xt * xt + 6 * (xt) * t
denominator = 6 * t + 4 * (xt)
# Performs big integer division, and then turns it into a decimal
return -Decimal(numerator // denominator) / Decimal(t)
from src.consensus.pos_quality import quality_str_to_quality
def calculate_iterations_quality(
@@ -49,12 +17,9 @@ def calculate_iterations_quality(
difficulty.
"""
min_iterations = min_block_time * vdf_ips
dec_iters = Decimal(int(difficulty) << 32) * (
_quality_to_decimal(quality) / _expected_plot_size(size)
)
iters_final = uint64(
int(min_iterations + dec_iters.to_integral_exact(rounding=ROUND_UP))
)
iters_rounded = (int(difficulty) << 32) // quality_str_to_quality(quality, size)
iters_final = uint64(min_iterations + iters_rounded)
assert iters_final >= 1
return iters_final
@@ -69,7 +34,7 @@ def calculate_iterations(
Convenience function to calculate the number of iterations using the proof instead
of the quality. The quality must be retrieved from the proof.
"""
quality: bytes32 = proof_of_space.verify_and_get_quality()
quality: bytes32 = proof_of_space.verify_and_get_quality_string()
return calculate_iterations_quality(
quality, proof_of_space.size, difficulty, vdf_ips, min_block_time
)
@@ -86,11 +51,10 @@ def calculate_ips_from_iterations(
other details, we can calculate the VDF speed (iterations per second) used to compute the
constant factor in iterations, which is not written into the block.
"""
quality: bytes32 = proof_of_space.verify_and_get_quality()
dec_iters = Decimal(int(difficulty) << 32) * (
_quality_to_decimal(quality) / _expected_plot_size(proof_of_space.size)
quality: bytes32 = proof_of_space.verify_and_get_quality_string()
iters_rounded = (int(difficulty) << 32) // quality_str_to_quality(
quality, proof_of_space.size
)
iters_rounded = int(dec_iters.to_integral_exact(rounding=ROUND_UP))
min_iterations = uint64(iterations - iters_rounded)
ips = min_iterations / min_block_time
assert ips >= 1
+32 -17
View File
@@ -62,8 +62,10 @@ class Farmer:
of space is sufficiently good, and if so, we ask for the whole proof.
"""
if challenge_response.quality in self.harvester_responses_challenge:
log.warning(f"Have already seen quality {challenge_response.quality}")
if challenge_response.quality_string in self.harvester_responses_challenge:
log.warning(
f"Have already seen quality string {challenge_response.quality_string}"
)
return
weight: uint64 = self.challenge_to_weight[challenge_response.challenge_hash]
height: uint32 = self.challenge_to_height[challenge_response.challenge_hash]
@@ -75,7 +77,7 @@ class Farmer:
raise RuntimeError("Did not find challenge")
number_iters: uint64 = calculate_iterations_quality(
challenge_response.quality,
challenge_response.quality_string,
challenge_response.plot_size,
difficulty,
self.proof_of_time_estimate_ips,
@@ -103,9 +105,11 @@ class Farmer:
or estimate_secs < self.config["propagate_threshold"]
):
self.harvester_responses_challenge[
challenge_response.quality
challenge_response.quality_string
] = challenge_response.challenge_hash
request = harvester_protocol.RequestProofOfSpace(challenge_response.quality)
request = harvester_protocol.RequestProofOfSpace(
challenge_response.quality_string
)
yield OutboundMessage(
NodeType.HARVESTER,
@@ -129,7 +133,9 @@ class Farmer:
if response.proof.pool_pubkey not in [sk.get_public_key() for sk in pool_sks]:
raise RuntimeError("Pool pubkey not in list of approved keys")
challenge_hash: bytes32 = self.harvester_responses_challenge[response.quality]
challenge_hash: bytes32 = self.harvester_responses_challenge[
response.quality_string
]
challenge_weight: uint64 = self.challenge_to_weight[challenge_hash]
challenge_height: uint32 = self.challenge_to_height[challenge_hash]
new_proof_height: uint32 = uint32(challenge_height + 1)
@@ -140,17 +146,17 @@ class Farmer:
if difficulty == 0:
raise RuntimeError("Did not find challenge")
computed_quality = response.proof.verify_and_get_quality()
if response.quality != computed_quality:
computed_quality_string = response.proof.verify_and_get_quality_string()
if response.quality_string != computed_quality_string:
raise RuntimeError("Invalid quality for proof of space")
self.harvester_responses_proofs[response.quality] = response.proof
self.harvester_responses_proofs[response.quality_string] = response.proof
self.harvester_responses_proof_hash_to_qual[
response.proof.get_hash()
] = response.quality
] = response.quality_string
number_iters: uint64 = calculate_iterations_quality(
computed_quality,
computed_quality_string,
response.proof.size,
difficulty,
self.proof_of_time_estimate_ips,
@@ -160,7 +166,8 @@ class Farmer:
if estimate_secs < self.config["pool_share_threshold"]:
request1 = harvester_protocol.RequestPartialProof(
response.quality, bytes.fromhex(self.key_config["farmer_target"]),
response.quality_string,
bytes.fromhex(self.key_config["farmer_target"]),
)
yield OutboundMessage(
NodeType.HARVESTER,
@@ -197,9 +204,15 @@ class Farmer:
Receives a signature on a block header hash, which is required for submitting
a block to the blockchain.
"""
header_hash: bytes32 = self.harvester_responses_header_hash[response.quality]
proof_of_space: bytes32 = self.harvester_responses_proofs[response.quality]
plot_pubkey = self.harvester_responses_proofs[response.quality].plot_pubkey
header_hash: bytes32 = self.harvester_responses_header_hash[
response.quality_string
]
proof_of_space: bytes32 = self.harvester_responses_proofs[
response.quality_string
]
plot_pubkey = self.harvester_responses_proofs[
response.quality_string
].plot_pubkey
assert response.header_hash_signature.verify(
[Util.hash256(header_hash)], [plot_pubkey]
@@ -224,7 +237,9 @@ class Farmer:
"""
farmer_target = bytes.fromhex(self.key_config["farmer_target"])
plot_pubkey = self.harvester_responses_proofs[response.quality].plot_pubkey
plot_pubkey = self.harvester_responses_proofs[
response.quality_string
].plot_pubkey
assert response.farmer_target_signature.verify(
[Util.hash256(farmer_target)], [plot_pubkey]
@@ -335,7 +350,7 @@ class Farmer:
self.unfinished_challenges[proof_of_space_arrived.weight] = []
else:
self.unfinished_challenges[proof_of_space_arrived.weight].append(
proof_of_space_arrived.quality
proof_of_space_arrived.quality_string
)
@api_request
+1 -1
View File
@@ -738,7 +738,7 @@ class FullNode:
request.challenge_hash,
bytes(request.proof_of_space.proof),
)
assert quality_string
assert len(quality_string) == 32
# Retrieves the correct tip for the challenge
tips: List[Header] = self.blockchain.get_current_tips()
+15 -16
View File
@@ -25,7 +25,7 @@ class Harvester:
# From filename to prover
self.provers: Dict[Path, DiskProver] = {}
# From quality to (challenge_hash, filename, index)
# From quality string to (challenge_hash, filename, index)
self.challenge_hashes: Dict[bytes32, Tuple[bytes32, Path, uint8]] = {}
self._plot_notification_task = asyncio.create_task(self._plot_notification())
self._is_shutdown: bool = False
@@ -94,7 +94,7 @@ class Harvester:
@api_request
async def new_challenge(self, new_challenge: harvester_protocol.NewChallenge):
"""
The harvester receives a new challenge from the farmer, and looks up the quality
The harvester receives a new challenge from the farmer, and looks up the quality string
for any proofs of space that are are found in the plots. If proofs are found, a
ChallengeResponse message is sent for each of the proofs found.
"""
@@ -114,16 +114,13 @@ class Harvester:
new_challenge.challenge_hash
)
for index, quality_str in enumerate(quality_strings):
quality = ProofOfSpace.quality_str_to_quality(
new_challenge.challenge_hash, quality_str
)
self.challenge_hashes[quality] = (
self.challenge_hashes[quality_str] = (
new_challenge.challenge_hash,
filename,
uint8(index),
)
response: harvester_protocol.ChallengeResponse = harvester_protocol.ChallengeResponse(
new_challenge.challenge_hash, quality, prover.get_size()
new_challenge.challenge_hash, quality_str, prover.get_size()
)
all_responses.append(response)
for response in all_responses:
@@ -143,10 +140,12 @@ class Harvester:
"""
response: Optional[harvester_protocol.RespondProofOfSpace] = None
try:
# Using the quality find the right plot and index from our solutions
challenge_hash, filename, index = self.challenge_hashes[request.quality]
# Using the quality string, find the right plot and index from our solutions
challenge_hash, filename, index = self.challenge_hashes[
request.quality_string
]
except KeyError:
log.warning(f"Quality {request.quality} not found")
log.warning(f"Quality string {request.quality_string} not found")
return
if index is not None:
proof_xs: bytes
@@ -170,7 +169,7 @@ class Harvester:
)
response = harvester_protocol.RespondProofOfSpace(
request.quality, proof_of_space
request.quality_string, proof_of_space
)
if response:
yield OutboundMessage(
@@ -187,10 +186,10 @@ class Harvester:
The farmer requests a signature on the header hash, for one of the proofs that we found.
A signature is created on the header hash using the plot private key.
"""
if request.quality not in self.challenge_hashes:
if request.quality_string not in self.challenge_hashes:
return
_, filename, _ = self.challenge_hashes[request.quality]
_, filename, _ = self.challenge_hashes[request.quality_string]
plot_sk = PrivateKey.from_bytes(
bytes.fromhex(self.plot_config["plots"][filename]["sk"])
@@ -203,7 +202,7 @@ class Harvester:
)
response: harvester_protocol.RespondHeaderSignature = harvester_protocol.RespondHeaderSignature(
request.quality, header_hash_signature,
request.quality_string, header_hash_signature,
)
yield OutboundMessage(
NodeType.FARMER,
@@ -220,7 +219,7 @@ class Harvester:
We look up the correct plot based on the quality, lookup the proof, and sign
the farmer target hash using the plot private key. This will be used as a pool share.
"""
_, filename, _ = self.challenge_hashes[request.quality]
_, filename, _ = self.challenge_hashes[request.quality_string]
plot_sk = PrivateKey.from_bytes(
bytes.fromhex(self.plot_config["plots"][filename]["sk"])
)
@@ -229,7 +228,7 @@ class Harvester:
)
response: harvester_protocol.RespondPartialProof = harvester_protocol.RespondPartialProof(
request.quality, farmer_target_signature
request.quality_string, farmer_target_signature
)
yield OutboundMessage(
NodeType.FARMER,
+2 -1
View File
@@ -25,8 +25,9 @@ class ProofOfSpaceFinalized:
@dataclass(frozen=True)
@cbor_message
class ProofOfSpaceArrived:
previous_challenge_hash: bytes32
weight: uint64
quality: bytes32
quality_string: bytes32
@dataclass(frozen=True)
+7 -7
View File
@@ -30,46 +30,46 @@ class NewChallenge:
@cbor_message
class ChallengeResponse:
challenge_hash: bytes32
quality: bytes32
quality_string: bytes32
plot_size: uint8
@dataclass(frozen=True)
@cbor_message
class RequestProofOfSpace:
quality: bytes32
quality_string: bytes32
@dataclass(frozen=True)
@cbor_message
class RespondProofOfSpace:
quality: bytes32
quality_string: bytes32
proof: ProofOfSpace
@dataclass(frozen=True)
@cbor_message
class RequestHeaderSignature:
quality: bytes32
quality_string: bytes32
header_hash: bytes32
@dataclass(frozen=True)
@cbor_message
class RespondHeaderSignature:
quality: bytes32
quality_string: bytes32
header_hash_signature: PrependSignature
@dataclass(frozen=True)
@cbor_message
class RequestPartialProof:
quality: bytes32
quality_string: bytes32
farmer_target_hash: bytes32
@dataclass(frozen=True)
@cbor_message
class RespondPartialProof:
quality: bytes32
quality_string: bytes32
farmer_target_signature: PrependSignature
+1 -1
View File
@@ -5,7 +5,7 @@ from src.types.sized_bytes import bytes32
from src.util.cbor_message import cbor_message
from src.util.ints import uint16
protocol_version = "0.0.4"
protocol_version = "0.0.5"
"""
Handshake when establishing a connection between two servers.
+2 -2
View File
@@ -23,7 +23,7 @@ class BLSSignature(Streamable):
@dataclass(frozen=True)
@streamable
class AGGSIGPair(Streamable):
class PkMessagePair(Streamable):
public_key: BLSPublicKey
message_hash: bytes32
@@ -39,7 +39,7 @@ class BLSSignature(Streamable):
sig = blspy.PrependSignature.aggregate(wrapped_sigs).serialize()
return cls(sig)
def validate(self, hash_key_pairs: List[AGGSIGPair]) -> bool:
def validate(self, hash_key_pairs: List[PkMessagePair]) -> bool:
# check for special case of 0
if len(hash_key_pairs) == 0:
return True
+2 -6
View File
@@ -22,7 +22,7 @@ class ProofOfSpace(Streamable):
def get_plot_seed(self) -> bytes32:
return self.calculate_plot_seed(self.pool_pubkey, self.plot_pubkey)
def verify_and_get_quality(self) -> Optional[bytes32]:
def verify_and_get_quality_string(self) -> Optional[bytes32]:
v: Verifier = Verifier()
plot_seed: bytes32 = self.get_plot_seed()
quality_str = v.validate_proof(
@@ -30,12 +30,8 @@ class ProofOfSpace(Streamable):
)
if not quality_str:
return None
return self.quality_str_to_quality(self.challenge_hash, quality_str)
return quality_str
@staticmethod
def calculate_plot_seed(pool_pubkey: PublicKey, plot_pubkey: PublicKey) -> bytes32:
return bytes32(sha256(bytes(pool_pubkey) + bytes(plot_pubkey)).digest())
@staticmethod
def quality_str_to_quality(challenge_hash: bytes32, quality_str: bytes) -> bytes32:
return bytes32(sha256(challenge_hash + quality_str).digest())
+3 -3
View File
@@ -72,14 +72,14 @@ def conditions_by_opcode(
def hash_key_pairs_for_conditions_dict(
conditions_dict: Dict[ConditionOpcode, List[ConditionVarPair]]
) -> List[BLSSignature.AGGSIGPair]:
pairs: List[BLSSignature.AGGSIGPair] = []
) -> List[BLSSignature.PkMessagePair]:
pairs: List[BLSSignature.PkMessagePair] = []
for cvp in conditions_dict.get(ConditionOpcode.AGG_SIG, []):
# TODO: check types
# assert len(_) == 3
blspubkey: BLSPublicKey = BLSPublicKey(cvp.var1)
message: bytes32 = bytes32(blspy.Util.hash256(cvp.var2))
pairs.append(BLSSignature.AGGSIGPair(blspubkey, message))
pairs.append(BLSSignature.PkMessagePair(blspubkey, message))
return pairs
+2 -23
View File
@@ -1,32 +1,11 @@
from decimal import Decimal
from hashlib import sha256
from math import log
from src.consensus.pot_iterations import (
_expected_plot_size,
_quality_to_decimal,
calculate_iterations_quality,
)
from src.consensus.pot_iterations import calculate_iterations_quality
from src.consensus.pos_quality import _expected_plot_size
from src.util.ints import uint8, uint64
class TestPotIterations:
def test_pade_approximation(self):
def test_approximation(input_dec, threshold):
bytes_input = int(Decimal(input_dec) * pow(2, 256)).to_bytes(32, "big")
print(_quality_to_decimal(bytes_input))
assert (
abs(1 - Decimal(-log(input_dec)) / _quality_to_decimal(bytes_input))
< threshold
)
# The approximations become better the closer to 1 the input gets
test_approximation(0.7, 0.01)
test_approximation(0.9, 0.001)
test_approximation(0.99, 0.00001)
test_approximation(0.9999, 0.0000001)
test_approximation(0.99999999, 0.0000000001)
def test_win_percentage(self):
"""
Tests that the percentage of blocks won is proportional to the space of each farmer,