難易度

7 件のメッセージ BitcoinTalk mizerydearia, Insti, サトシ・ナカモト, ArtForz 2010年7月27日 — 2010年8月4日
mizerydearia 2010年7月27日 10:11 UTC 原文 ·

http://nullvoid.org/bitcoin/difficultiez.php

<?
	header("Content-type: text/html");
	require_once 'jsonRPCClient.php';
	$data=new jsonRPCClient('http://127.0.0.1:8332');
	$blockcount = $data->getblockcount();
	$now = date("U");
	$blockfile = "blockdata";
	$data = file($blockfile, FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES); array_pop($data);
?><html>
 <head>
  <meta http-equiv="refresh" content="100000">
 </head>
 <body>
  <pre>
<?
	function humantime($secs) {
		if ($secs<0) return false;
		$m = (int)($secs / 60); $s = $secs % 60; $s = ($s <= 9) ? "0$s" : $s;
		$h = (int)($m / 60); $m = $m % 60; $m = ($m <= 9) ? "0$m" : $m;
		$d = (int)($h / 24); $h = $h % 24; $h = ($h <= 9) ? "0$h" : $h;
		$d = ($d <= 9) ? "0$d" : $d;
		return $d."d $h:$m:$s";
	}

	// Converted from ArtForz's python code http://bitcointalk.org/index.php?topic=464.msg4080#msg4080
	function uint256_from_compact($c) {
		$nbytes = ($c >> 24) & 0xFF;
		return bcmul($c & 0xFFFFFF,bcpow(2,8 * ($nbytes - 3)));
	}
	
	$tblock = 0;
	$nTargetTimespan = 60 * 60 * 24 * 14;
	bcscale(256);
	foreach ($data as $line) {
		$blocks = strtok($line, " ");
		$date = strtok(" ");
		$avghash = strtok(" ");
		$bits = strtok(" ");
		if ($blocks == 0 || $blocks == $tblock) {
			$tblock = $blocks + 2016;
			$blocknum = str_repeat(" ", 6 - strlen($blocks)).$blocks;
			echo "Block $blocknum was generated at $date (".date("r", $date).")";
			if ($blocks != 0) {
				$intervalnum = $date - $lastdate;
				$interval = str_repeat(" ", 9 - strlen($intervalnum)).$intervalnum;
				echo "    $interval seconds interval (".humantime($intervalnum).")";
				echo "   Difficulty: ".bcdiv(bcdiv(bcmul(uint256_from_compact(0x1D00FFFF),1000), uint256_from_compact($bits)), 1000);
				$lastdate = $date;
			}
			echo "<br>";
		}
	}
?>
  </pre>
 </body>
</html>
Insti 2010年7月27日 15:45 UTC 原文 ·

難易度が 244.213223092375323881335701184896212407930361873708113773326734402748260502489 1554339282075169582811726687822061777635447902413461818393548574922122914786456 6654051064077556842993973623686279076537890477160907158869253835628402573582928 17840402922938076799907 じゃなくて本当に良かった

その場合、ブロックを獲得するのがどれだけ大変か想像してみてくれ!!!!!

mizerydearia 2010年7月28日 00:31 UTC 原文 ·

実際、もう 1 桁追加して計算すると 244.213223092375323881335701184896212407930361873708113773326734402748260502489 1554339282075169582811726687822061777635447902413461818393548574922122914786456 6654051064077556842993973623686279076537890477160907158869253835628402573582928 178404029229380767999068 となり、Insti が示した値に切り上げられる。

見ていたコードが間違っている。適用されるコードはこちらだ:

bool CBlock::CheckBlock() const
{
...
    // タイムスタンプをチェック
    if (nTime > GetAdjustedTime() + 2 * 60 * 60)
        return error("CheckBlock() : block timestamp too far in the future");
...

bool CBlock::AcceptBlock()
{
   ...
    // 前のブロックに対してタイムスタンプをチェック
    if (nTime <= pindexPrev->GetMedianTimePast())
        return error("AcceptBlock() : block's timestamp is too early");

タイムスタンプは未来方向には最大 2時間に制限されている。前のブロックより早い時刻にすることはできるが、直近 11 ブロックの中央値より大きくなければならない。このようにしている理由は、前のブロックのタイムスタンプが未来すぎた場合(今回起きたように)、次のブロックで時刻を修正できるようにするためだ。

mizerydearia 2010年8月4日 09:06 UTC 原文 ·

C++の SetCompact(unsigned int nCompact)関数が以下のようだとして、

CBigNum& SetCompact(unsigned int nCompact) {
    unsigned int nSize = nCompact >> 24;
    std::vector<unsigned char> vch(4 + nSize);
    vch[3] = nSize;
    if (nSize >= 1) vch[4] = (nCompact >> 16) & 0xff;
    if (nSize >= 2) vch[5] = (nCompact >> 8) & 0xff;
    if (nSize >= 3) vch[6] = (nCompact >> 0) & 0xff;
    BN_mpi2bn(&vch[0], vch.size(), this);
    return *this;
}
これに対応するPythonが
def uint256_from_compact(c):
	nbytes = (c >> 24) & 0xFF
	v = (c & 0xFFFFFFL) << (8 * (nbytes - 3))
	return v
対応するPHPが
function uint256_from_compact($c) {
	$nbytes = ($c >> 24) & 0xFF;
	return bcmul($c & 0xFFFFFF,bcpow(2,8 * ($nbytes - 3)));
}

そして、C++の Getcompact()関数

unsigned int GetCompact() const {
    unsigned int nSize = BN_bn2mpi(this, NULL);
    std::vector<unsigned char> vch(nSize);
    nSize -= 4;
    BN_bn2mpi(this, &vch[0]);
    unsigned int nCompact = nSize << 24;
    if (nSize >= 1) nCompact |= (vch[4] << 16);
    if (nSize >= 2) nCompact |= (vch[5] << 8);
    if (nSize >= 3) nCompact |= (vch[6] << 0);
    return nCompact;
}

であるとき、C++の Getcompact()関数に対応する Python/PHP の単純なコードはどう書けばいい?

この php スニペットの中で関数を使うつもりだ

function GetNextWorkRequired($block, $bits, $nActualTimespan) {
	$nTargetTimespan = 60 * 60 * 24 * 14; // 2 weeks
	if ($nActualTimespan < $nTargetTimespan / 4) { $nActualTimespan = $nTargetTimespan / 4; }
	if ($nActualTimespan > $nTargetTimespan * 4) { $nActualTimespan = $nTargetTimespan * 4; }
	$bits = uint256_from_compact($bits);
	$bits = bcmul($bits,$nActualTimespan);
	$bits = bcdiv($bits,$nTargetTimespan);
	$bits = uint256_to_compact($bits); // <-- Need to translate C++ code for GetCompact()
	return $bits;
}
ArtForz 2010年8月4日 14:21 UTC 原文 ·

これが Python 向けの俺の手早く雑な参照実装だ。-256〜256 の範囲と、8〜256 ビットでサイズの異なるランダムな数値約 4000個について、Bitcoin の実装と照らし合わせてテスト済みだ。 もっと速く Python らしいバージョンを書くのは簡単なはずだが、今はその気になれない…

import struct

def mpi2num(m):
	"""convert MPI string to number"""
	datasize = struct.unpack(">I", m[0:4])[0]
	r = 0
	if datasize:
		neg_flag = bool(ord(m[4]) & 0x80)
		r = ord(m[4]) & 0x7F
		for i in xrange(1, datasize):
			r <<= 8
			r += ord(m[4+i])
		if neg_flag:
			r = -r
	return r

def num2mpi(n):
	"""convert number to MPI string"""
	if n == 0:
		return struct.pack(">I", 0)
	r = ""
	neg_flag = bool(n < 0)
	n = abs(n)
	while n:
		r = chr(n & 0xFF) + r
		n >>= 8
	if ord(r[0]) & 0x80:
		r = chr(0) + r
	if neg_flag:
		r = chr(ord(r[0]) | 0x80) + r[1:]
	datasize = len(r)
	return struct.pack(">I", datasize) + r

def GetCompact(n):
	"""convert number to bc compact uint"""
	mpi = num2mpi(n)
	nSize = len(mpi) - 4
	nCompact = (nSize & 0xFF) << 24
	if nSize >= 1:
		nCompact |= (ord(mpi[4]) << 16)
	if nSize >= 2:
		nCompact |= (ord(mpi[5]) << 8)
	if nSize >= 3:
		nCompact |= (ord(mpi[6]) << 0)
	return nCompact

def SetCompact(nCompact):
	"""convert bc compact uint to number"""
	nSize = (nCompact >> 24) & 0xFF
	tbuf = "\x00\x00\x00" + chr(nSize)
	if nSize >= 1:
		tbuf += chr((nCompact >> 16) & 0xFF)
	if nSize >= 2:
		tbuf += chr((nCompact >> 8) & 0xFF)
	if nSize >= 3:
		tbuf += chr((nCompact >> 0) & 0xFF)
		tbuf += "\x00" * (nSize - 3)
	return mpi2num(tbuf)
mizerydearia 2010年8月4日 14:45 UTC 原文 ·

ArtForz ありがとう! ^_^

ArtForzの投稿(2010年8月4日 14:21 UTC)

Code:import struct

def SetCompact(nCompact): """convert bc compact uint to number""" nSize = (nCompact >> 24) & 0xFF tbuf = “\x00\x00\x00” + chr(nSize) if nSize >= 1: tbuf += chr((nCompact >> 16) & 0xFF) if nSize >= 2: tbuf += chr((nCompact >> 8) & 0xFF) if nSize >= 3: tbuf += chr((nCompact >> 0) & 0xFF) tbuf += “\x00” * (nSize - 3) return mpi2num(tbuf)

def uint256_from_compact(c):
	nbytes = (c >> 24) & 0xFF
	v = (c & 0xFFFFFFL) << (8 * (nbytes - 3))
	return v
これら両方が0x1d00ffffを使ったとき同じ出力を生成することを改めて確認した