0

我正在研究区块链,并且正在实施一个非常简单的“工作证明”。

工作证明:

export function mineBlock(difficulty: number, block) {
  const prefix = Array(difficulty + 1).join("0");

  function mine(block, difficulty) {
    const nonce = block.nonce + 1;
    const newBlock = {...block, nonce};
    const hash = calculateHash(newBlock);

    return hash.substring(0, difficulty) === prefix
                ? {...newBlock, hash}
                : mine({...newBlock, hash}, difficulty);
  }

  return trampoline(mine(block, difficulty));

}

蹦床:

export function trampoline(func) {
  let result = func;

  while(result && typeof(result) === "function") {
    result = result();
  }

  return result;
}

我仍然收到“超出最大调用堆栈大小”错误,甚至是蹦床mine功能。

我在 StackOverflow 上阅读了很多其他问题以及各种博客上的文章,但其中很多只关注“阶乘”或“斐波那契”示例,其中蹦床或 TCE 解决了问题……但事实并非如此。

我正在使用 Node 10,所以我不介意这在浏览器中是否不起作用。

4

1 回答 1

2

根据您的蹦床 -

export function trampoline(func) {
  let result = func;

  while(result && typeof(result) === "function") { // <--
    result = result();
  }

  return result;
}

你可能打算——

function mineBlock(difficulty, block) {
  const prefix = Array(difficulty + 1).join("0");

  function mine(block, difficulty) {
    const nonce = block.nonce + 1;
    const newBlock = {...block, nonce};
    const hash = calculateHash(newBlock);

    return hash.substring(0, difficulty) === prefix
                ? {...newBlock, hash}
                  // add `() => ...`
                : () => mine({...newBlock, hash}, difficulty); // <--
  }

  return trampoline(mine(block, difficulty));
}

但不要止步于此。difficulty被不必要地遮蔽。它是 的一个参数mine,但它在重复调用中永远不会改变。你可以删除它

function mineBlock(difficulty, block) {
  const prefix = Array(difficulty + 1).join("0")

  function mine(block) { // <--
    const nonce = block.nonce + 1
    const newBlock = {...block, nonce}
    const hash = calculateHash(newBlock)

    return hash.substring(0, difficulty) === prefix
                ? {...newBlock, hash}
                : () => mine({...newBlock, hash}) // <--
  }

  return trampoline(mine(block)) // <--
}

看看你是如何写成calculateHash一个单独的函数的?您将“检查难度”与“挖矿”混为一谈。这也应该是一个单独的功能 -

function checkDifficulty(n, hash) {
  return hash.substr(0,n) === "0".repeat(n)
}

function mineBlock(difficulty, block) {
  function mine(block) { 
    const nonce = block.nonce + 1
    const newBlock = {...block, nonce}
    const hash = calculateHash(newBlock)

    return checkDifficulty(difficulty, hash) // <--
                ? {...newBlock, hash}
                : () => mine({...newBlock, hash})
  }

  return trampoline(mine(block)) // <--
}

单独关注更新随机数和散列 -

function checkDifficulty(n, hash) {
  return hash.substr(0,n) === "0".repeat(n)
}

function nextNonce(block) {
  return updateHash({ ...block, nonce: block.nonce + 1 })
}

function updateHash(block) {
  return { ...block, hash: calculateHash(block) }
}

function mineBlock(difficulty, block) {
  function mine(block) {
    const newBlock = nextNonce(block) // <--

    return checkDifficulty(difficulty, newBlock.hash)
                ? newBlock
                : () => mine(newBlock)
  }

  return trampoline(mine(block)) // <--
}

mine最后,通过将nextNonce调用移出循环来简化

function checkDifficulty(n, hash) {
  return hash.substr(0,n) === "0".repeat(n)
}

function nextNonce(block) {
  return updateHash({ ...block, nonce: block.nonce + 1 })
}

function updateHash(block) {
  return { ...block, hash: calculateHash(block) }
}

function mineBlock(difficulty, block) {
  function mine(b) {
    return checkDifficulty(difficulty, b.hash)
                ? b
                : () => mine(nextNonce(b)) // <--
  }

  return trampoline(mine(nextNonce(block)) // <--
}

这些只是您可以在沙子中绘制的可能线条。希望这能让您了解如何开始改进您的程序。您可能会选择绘制不同的线条,这没关系。

我们现在可以使用一个简单的while循环 -

function mineBlock(difficulty, block) {
  let b = block
  while (!checkDifficulty(difficulty, b.hash))
    b = nextNonce(b)
  return b
}

或者完全不同的蹦床——

const loop = f =>
{ let a = f ()
  while (a && a.recur === recur)
    a = f (...a.values)
  return a
}

const recur = (...values) =>
  ({ recur, values })

const mineBlock = (difficulty, block) =>
  loop
    ( (b = block) =>
        checkDifficulty (difficulty, b)
          ? b
          : recur (nextNonce (b))
    )
于 2019-04-19T13:38:20.670 回答