cardano-miners / fortuna

All the "greatness" of proof of work, now in smart contract form
https://minefortuna.com
Apache License 2.0
52 stars 23 forks source link

A question about validating previously blocks #12

Closed vegas-hosky closed 1 year ago

vegas-hosky commented 1 year ago

I hope it's alright to ask questions, but I have one.... ;-)

When I look at the mining code, I can't help but question one bit of logic. The Nonce is a random value that is used to double SHA the block details until the threshold of difficultly and leading zeros are found. However, when the block is 'mined', the nonce is NOT written to the transaction DATUM.

How is one meant to be able to validate previous blocks are correct? I've been toying with the idea of writing a little miner myself, but I wanted to make sure existing blocks validate via my code.

Is it possible? Clearly I'm missing something here, as it logically should be possible?

MicroProofs commented 1 year ago

The nonces are passed in by redeemer for the tx. Maybe I could have included the nonce in the datum state. But there is always room to experiment.

vegas-hosky commented 1 year ago

Ah, so I should be able to look that up in the transaction and use it to recalculate! That's perfectly fine. A bit more clunky on look up.. Will research. Thanks for the answer.

vegas-hosky commented 1 year ago

Hi there,

This is driving me nuts and I need to get it checked with you. Forgive me, as I've made a mistake somewhere and would love your direction. I've also not used typescript before.

I'm looking at Block 1 (https://cardanoscan.io/transaction/7d7639904fa8ed2dc2c29050bfc4ec68634de7ff544053a88c8b657b072907a3?tab=utxo)

This block is computed (by my understanding from the Genesis block, that we got to witness at Rare Evo.

So we take the datum from that:

d5082004792551a60d171cae0051823180dd5c626a9bbbc889e8598395fa8ddd

{
   constructor: 0,
   fields: [
      {
         int: 0
      },
      {
         bytes: "e4390b57fd759b5961107b931dca6d826cb2c272f0f711e266df48d0afc3a441"
      },
      {
         int: 5
      },
      {
         int: 65535
      },
      {
         int: 0
      },
      {
         int: 1693078039000
      },
      {
         int: 0
      },
      []
   ]
}

With this, we use the Nonce that was in the redeemer, which I find to be:

{"fields": [{"bytes": "50757d0867a391511f23ad470f2fcc71"}], "constructor": 1}

When we look at block 1, it has the following Current Hash of

0000023bf7bf1be07d7ae46e69ec7d22d5af2d29fb1df138d703ec470eb64740

Which meets the leading zero and difficulty level.

So this is the Hash that should be calculated by the above information, if I've read it right. So I've then taken your code and simplified it for just the double SHA:

import { sha256, Constr, fromHex, toHex, Data } from "https://deno.land/x/lucid@0.10.1/mod.ts";

const NONCE = "50757d0867a391511f23ad470f2fcc71"
const BLOCK_NO = 0
const CURRENT_HASH = "e4390b57fd759b5961107b931dca6d826cb2c272f0f711e266df48d0afc3a441"
const LEADING_ZEROS = 5
const DIFFICULTY = 65535
const EPOCH_TIME = 1693078039000
const EXPECT_HASH = "0000023bf7bf1be07d7ae46e69ec7d22d5af2d29fb1df138d703ec470eb64740"

const targetState = new Constr(0, [
  NONCE,
  BigInt(BLOCK_NO),
  BigInt("0x"+CURRENT_HASH),
  BigInt(LEADING_ZEROS),
  BigInt(DIFFICULTY),
  BigInt(EPOCH_TIME)
]);

console.log(targetState);

const targetHash = sha256(sha256(fromHex(Data.to(targetState))));

// Convert the target hash to a hexadecimal string
const targetHashHex = toHex(targetHash)

console.log("Target State: ", targetState);
console.log("Target Hash: ", targetHashHex);
console.log("Expect Hash: ", EXPECT_HASH);

You'll have to forgive my coding style/convention. However, when I run this, the hash does not match:

Constr {
  index: 0,
  fields: [
    "50757d0867a391511f23ad470f2fcc71",
    0n,
    103228118051094669631097020313202500125925269564905190500216184067248688964673n,
    5n,
    65535n,
    1693078039000n
  ]
}
Target State:  Constr {
  index: 0,
  fields: [
    "50757d0867a391511f23ad470f2fcc71",
    0n,
    103228118051094669631097020313202500125925269564905190500216184067248688964673n,
    5n,
    65535n,
    1693078039000n
  ]
}
Target Hash:  da5f5edb92dcfe338f1c1fefaa8f526ded9c495d689d4b5a32aa72939dd56d0f
Expect Hash:  0000023bf7bf1be07d7ae46e69ec7d22d5af2d29fb1df138d703ec470eb64740

I assume I've either picked the wrong datum OR have a coding problem, because the Target Hash does not match the expected.

Can you put me out of my misery and identify why I'm being so stupid?

MicroProofs commented 1 year ago

cbor encodes bytearray and int differently so this line BigInt("0x"+CURRENT_HASH), is wrong

vegas-hosky commented 1 year ago

Just updated my example as I pasted the redeemer value from block 2... Just trying your suggestion.

vegas-hosky commented 1 year ago

Sorry to follow up,

Are you suggesting this:

const targetState = new Constr(0, [
  NONCE,
  BigInt(BLOCK_NO),
  CURRENT_HASH,
  BigInt(LEADING_ZEROS),
  BigInt(DIFFICULTY),
  BigInt(EPOCH_TIME)
]);

That still results in:

Target Hash:  117f9f3d3f4d763fd1df76547d87b1ece48fa97aa65b44cab6c97554cc91db9b
Expect Hash:  0000023bf7bf1be07d7ae46e69ec7d22d5af2d29fb1df138d703ec470eb64740

Getting closer (if you squint). As stated, I'm not a Typescript expert, but have tried to reuse all functions already in your code. I'm assuming a bug or I've pulled the wrong nonce value!?

MicroProofs commented 1 year ago

I'd have to see your target hash cbor. I'm not sure what else is different. remember nonce and current hash are hex encoded strings in lucid.

vegas-hosky commented 1 year ago

Thanks, I'll keep digging..

d8799f5050757d0867a391511f23ad470f2fcc71005820e4390b57fd759b5961107b931dca6d826cb2c272f0f711e266df48d0afc3a4410519ffff1b0000018a3350a9d8ff

Is generated. I'm obviously doing something wrong. So I'll keep persevering with it.

MicroProofs commented 1 year ago

You can always double check with the emulator on lucid. If I run into anything I'll let you know.

vegas-hosky commented 1 year ago

Whoop!!

I've figured it. I've been copying in the wrong epoch time! I've been picking up the now + 9000 one...

It's all now validating nicely. Thanks and sorry to have troubled.

I'll close this, but before I do, here's my amended code as proof:

import { sha256, Constr, fromHex, toHex, Data } from "https://deno.land/x/lucid@0.10.1/mod.ts";

const NONCE = "50757D0867A391511F23AD470F2FCC71"
const BLOCK_NO = 0
const CURRENT_HASH = "E4390B57FD759B5961107B931DCA6D826CB2C272F0F711E266DF48D0AFC3A441"
const LEADING_ZEROS = 5
const DIFFICULTY = 65535
const EPOCH_TIME = 0
const EXPECT_HASH = "0000023bf7bf1be07d7ae46e69ec7d22d5af2d29fb1df138d703ec470eb64740"

/*
const NONCE = "6D7D98E4685C3F7944985859ED22DFF7"
const BLOCK_NO = 1
const CURRENT_HASH = "0000023BF7BF1BE07D7AE46E69EC7D22D5AF2D29FB1DF138D703EC470EB64740"
const LEADING_ZEROS = 5
const DIFFICULTY = 65535
const EPOCH_TIME = 252000
const EXPECT_HASH = "000009674c6f06d38294e349ee8a56cd3944be2377e721ea295a714972f192b4"
*/

const targetState = new Constr(0, [
  NONCE,
  BigInt(BLOCK_NO),
  CURRENT_HASH,
  BigInt(LEADING_ZEROS),
  BigInt(DIFFICULTY),
  BigInt(EPOCH_TIME)
]);

console.log(targetState);

console.log(Data.to(targetState));

const targetHash = sha256(sha256(fromHex(Data.to(targetState))));

// Convert the target hash to a hexadecimal string
const targetHashHex = toHex(targetHash)

console.log("Target State: ", targetState);
console.log("Target Hash: ", targetHashHex);
console.log("Expect Hash: ", EXPECT_HASH);
vegas-hosky commented 1 year ago

Thanks and sorry to take your time. Now my real work can begin on this.

MicroProofs commented 1 year ago

Excellent