【Blockchain】Cardanoのノードの稼働

### 依存パッケージのインストール
$ sudo apt update
$ sudo apt install -y libssl-dev build-essential m4 jq curl

MithrilクライアントはRustで開発されている

### Rustツールチェーンのインストール
$ curl –proto ‘=https’ –tlsv1.2 -sSf https://sh.rustup.rs | sh
$ source $HOME/.cargo/env
$ rustup install stable
$ rustup default stable
$ rustup update
$ rustup component add clippy rustfmt
$ rustup target add x86_64-unknown-linux-musl

Mithrilクライアントは、Cardanoノードのデータベースを迅速に同期するためのツール

$ git clone https://github.com/input-output-hk/mithril.git
$ cd mithril
$ ls
CHANGELOG.md NOTICE internal mithril-install.sh
CODE-OF-CONDUCT.md README.md mithril-aggregator mithril-relay
CONTRIBUTING.md SECURITY.md mithril-client mithril-signer
Cargo.lock demo mithril-client-cli mithril-stm
Cargo.toml docs mithril-client-wasm mithril-test-lab
DEV-ADR.md examples mithril-common networks.json
LICENSE flake.lock mithril-explorer openapi.yaml
Makefile flake.nix mithril-infra
$ git fetch –all –prune
$ git checkout tags/2403.1

$ cd mithril-client-cli
$ make build

$ ./mithril-client -V
$ sudo mv mithril-client /usr/local/bin/mithril-client

$ mithril-client cardano-db snapshot list
$ mithril-client cardano-db snapshot download –snapshot-id

【Blockchain】ethereumのlight nodeをサーバで動かしたい

### ubuntuにaptよりインストール
$ sudo add-apt-repository -y ppa:ethereum/ethereum
$ sudo apt update
$ sudo apt install -y geth

### light modeについて
$ geth –syncmode “light”
INFO [06-02|12:21:33.754] Starting Geth on Ethereum mainnet…
INFO [06-02|12:21:33.756] Bumping default cache on mainnet provided=1024 updated=4096
INFO [06-02|12:21:33.762] Maximum peer count ETH=50 total=50
INFO [06-02|12:21:33.767] Smartcard socket not found, disabling err=”stat /run/pcscd/pcscd.comm: no such file or directory”
WARN [06-02|12:21:33.773] Sanitizing cache to Go’s GC limits provided=4096 updated=654
Fatal: –syncmode: unknown sync mode “light”, want “full” or “snap”
lightクライアント機能は削除されている模様

### snap (軽量なフルノード)
数時間で同期可能
400GB以上が必要
$ geth –syncmode=snap

【Blockchain】storjをpythonで実装する

import os
from cryptography.fernet import Fernet
from reedsolo import RSCodec

CHUNK_SIZE = 32
DATA_SEGMENTS = 4
TOTAL_SEGMENTS = 8
rsc = RSCodec(TOTAL_SEGMENTS - DATA_SEGMENTS)

key = Fernet.generate_key()
cipher = Fernet(key)

original_data = b"StorjTestData1234567890!ThisIsAChunkTestFile!!"
print(f"元データ: {original_data}")

encrypted_data = cipher.encrypt(original_data)
print(f"暗号化データ: {encrypted_data}")

chunks = [encrypted_data[i:i+CHUNK_SIZE] for i in range(0, len(encrypted_data), CHUNK_SIZE)]

def encode_chunk(chunk):
    encoded = rsc.encode(chunk)
    seg_size = len(encoded) // TOTAL_SEGMENTS
    return [encoded[i:i+seg_size] for i in range(0, len(encoded), seg_size)]

distributed_chunks = []
for chunk in chunks:
    segments = encode_chunk(chunk)
    distributed_chunks.append(segments)

for i, chunk_segs in enumerate(distributed_chunks):
    print(f"\n チャンク{i+1}:")
    for j, seg in enumerate(chunk_segs):
        print(f" ノード{j}: {seg}")

def recover_chunk(pieces):
    combined = b''.join(pieces)
    return rsc.decode(combined)

recovered_encrypted = b''
for chunk_segs in distributed_chunks:
    selected_pieces = chunk_segs[:DATA_SEGMENTS]
    recovered = recover_chunk(selected_pieces)
    recovered_encrypted += recovered

decrypted_data = cipher.decrypt(recoved_encrypted)
print(f"\n復元された平文: {decrypted_data}")

$ python3 storj.py
元データ: b’StorjTestData1234567890!ThisIsAChunkTestFile!!’
暗号化データ: b’gAAAAABoLw7a8YpRJbYfA1bt6JOd9Rn28BVtmziV9-qXo9pWs41Or5LN8J0J3UKgAB7uTmpXjkHgTiEv_Dn4ajnfJATxU4lkoOS8xI67SmVeORdvPm6O6OEqGYBXfhQAGaBEtun2jHOw’

チャンク1:
ノード0: bytearray(b’gAAA’)
ノード1: bytearray(b’AABo’)
ノード2: bytearray(b’Lw7a’)
ノード3: bytearray(b’8YpR’)
ノード4: bytearray(b’JbYf’)
ノード5: bytearray(b’A1bt’)
ノード6: bytearray(b’6JOd’)
ノード7: bytearray(b’9Rn2′)
ノード8: bytearray(b”3\’\xf8\xd8″)

チャンク2:
ノード0: bytearray(b’8BVt’)
ノード1: bytearray(b’mziV’)
ノード2: bytearray(b’9-qX’)
ノード3: bytearray(b’o9pW’)
ノード4: bytearray(b’s41O’)
ノード5: bytearray(b’r5LN’)
ノード6: bytearray(b’8J0J’)
ノード7: bytearray(b’3UKg’)
ノード8: bytearray(b’\x1b\xe3=\xc7′)

チャンク3:
ノード0: bytearray(b’AB7u’)
ノード1: bytearray(b’TmpX’)
ノード2: bytearray(b’jkHg’)
ノード3: bytearray(b’TiEv’)
ノード4: bytearray(b’_Dn4′)
ノード5: bytearray(b’ajnf’)
ノード6: bytearray(b’JATx’)
ノード7: bytearray(b’U4lk’)
ノード8: bytearray(b’t\x915\xa3′)

チャンク4:
ノード0: bytearray(b’oOS8′)
ノード1: bytearray(b’xI67′)
ノード2: bytearray(b’SmVe’)
ノード3: bytearray(b’ORdv’)
ノード4: bytearray(b’Pm6O’)
ノード5: bytearray(b’6OEq’)
ノード6: bytearray(b’GYBX’)
ノード7: bytearray(b’fhQA’)
ノード8: bytearray(b’e\x02al’)

チャンク5:
ノード0: bytearray(b’Ga’)
ノード1: bytearray(b’BE’)
ノード2: bytearray(b’tu’)
ノード3: bytearray(b’n2′)
ノード4: bytearray(b’jH’)
ノード5: bytearray(b’Ow’)
ノード6: bytearray(b’\x00\xea’)
ノード7: bytearray(b’\x8b\x07′)

【Blockchain】siaをpythonで実装する

データをchunkして、encodeして、セグメントに分割して、nodeに保存する

import math
from reedsolo import RSCodec
import random

SEGMENT_SIZE = 8
DATA_SEGMENTS = 4
TOTAL_SEGMENTS = 6
CHUNK_SIZE = SEGMENT_SIZE * DATA_SEGMENTS

rsc = RSCodec(TOTAL_SEGMENTS - DATA_SEGMENTS)

def generate_fake_file(size=40):
    return bytearray([random.randint(0, 255) for _ in range(size)])

def split_into_chunks(data, chunk_size):
    return [data[i:i+chunk_size] for i in range(0, len(data), chunk_size)]

def encode_chunk(chunk):
    segments = [chunk[i:i+SEGMENT_SIZE] for i in range(0, len(chunk), SEGMENT_SIZE)]

    joined_data = b''.join(segments)
    encoded = rsc.encode(joined_data)

    seg_len = len(encoded) // TOTAL_SEGMENTS
    encoded_segments = [encoded[i:i+seg_len] for i in range(0, len(encoded), seg_len)]

    return encoded_segments

def distribute_segments(segments):
    nodes = {}
    for i, seg in enumerate(segments):
        nodes[f"node_{i}"] = seg
    return nodes


fake_file = generate_fake_file(40)
print(fake_file)

chunks = split_into_chunks(fake_file, CHUNK_SIZE)
for i, chunk in enumerate(chunks):
    print(f"チャンク {i+1}: {chunk}")

    encoded_segments = encode_chunk(chunk)
    print(f" ↳ 符号化セグメント数: {len(encoded_segments)} ")

    distributed = distribute_segments(encoded_segments)
    for node, seg in distributed.items():
        print(f" {node}に保存: {seg}")
    print()

$ python3 sia.py
bytearray(b”Xz\xe12\x1a\xe7aq\xf3\’\x11\xcb\xa7\xf0\x0f*r\xd5Y4y#|\xb2\xe0\xeb\xb4\x14+\xedl\xe2\xf9\x1b\xe9s\x93\xc0\x94\xde”)
チャンク 1: bytearray(b”Xz\xe12\x1a\xe7aq\xf3\’\x11\xcb\xa7\xf0\x0f*r\xd5Y4y#|\xb2\xe0\xeb\xb4\x14+\xedl\xe2″)
↳ 符号化セグメント数: 7
node_0に保存: bytearray(b’Xz\xe12\x1a’)
node_1に保存: bytearray(b”\xe7aq\xf3\'”)
node_2に保存: bytearray(b’\x11\xcb\xa7\xf0\x0f’)
node_3に保存: bytearray(b’*r\xd5Y4′)
node_4に保存: bytearray(b’y#|\xb2\xe0′)
node_5に保存: bytearray(b’\xeb\xb4\x14+\xed’)
node_6に保存: bytearray(b’l\xe2q\xac’)

チャンク 2: bytearray(b’\xf9\x1b\xe9s\x93\xc0\x94\xde’)
↳ 符号化セグメント数: 10
node_0に保存: bytearray(b’\xf9′)
node_1に保存: bytearray(b’\x1b’)
node_2に保存: bytearray(b’\xe9′)
node_3に保存: bytearray(b’s’)
node_4に保存: bytearray(b’\x93′)
node_5に保存: bytearray(b’\xc0′)
node_6に保存: bytearray(b’\x94′)
node_7に保存: bytearray(b’\xde’)
node_8に保存: bytearray(b’\xb9′)
node_9に保存: bytearray(b’\xd8′)

【Rust】getblockのCLIコマンド機能を作る

CLIでgetblockと引数にblock heightのi32を受け取って、ブロック情報を表示します。

#[derive(Subcommand)]
enum Command {
  Getnewaddress,
  Getinfo,
  Getbalance(BalanceArgs),
  Getaccount,
  Getblock(BlockArgs),
}

fn main() {
   let args = App::parse();
   match args.command {
      Command::Getnewaddress => getnewaddress(),
      Command::Getinfo => getinfo(),
      Command::Getbalance(args) => args.run(),
      Command::Getaccount => getaccount(),
      Command::Getblock(args) => args.run(),
   }
}

#[derive(Args)]
struct BlockArgs {
  height: i32,
}

impl BlockArgs {
  fn run(&self) {
    let _ = cli::get_block(self.height);
  }
}

$ ./target/debug/ruscal getblock 8
Block { height: 8, version: “0.1.0”, time: 2025-02-25T06:48:54.561868021Z, transactions: [SignedTransaction { version: “0.1.0”, time: 2025-02-25T06:47:49.809920514Z, sender: “0410f87429e89498e928d00b6a6186fdc9ccbde2ca55d5746f0e1bf8f1a1fbdb7634de5c1d5b4e49dc29bb78613fefb199d93eb8eb73545791a245c1f1ca6d5ce0”, receiver: “1FsHydJvr3nKj3KcwFhSozBf2WBKMf9jeo”, amount: 50, nft_data: “”, nft_origin: “”, op_code: “”, signature: “8A5216CD62C309A4923E9088CA9284AFC7C0261D89754FCE84735EC34A193A089B7A4C62FC32F91AE0B83549D575CE3D5EBAC1C4B9A61F0EF67D1B851F3F3E53” }, SignedTransaction { version: “0.1.0”, time: 2025-02-25T06:48:45.817409745Z, sender: “0410f87429e89498e928d00b6a6186fdc9ccbde2ca55d5746f0e1bf8f1a1fbdb7634de5c1d5b4e49dc29bb78613fefb199d93eb8eb73545791a245c1f1ca6d5ce0”, receiver: “1FsHydJvr3nKj3KcwFhSozBf2WBKMf9jeo”, amount: 60, nft_data: “”, nft_origin: “”, op_code: “”, signature: “6E73E636DDA5A5F360280442BEA308CD3C38C7A4C769BC8D4965B5106F9F6647D15B0382DE90ECFB84AE462BB81F26099DB1F8A9F0276541C44C60376FF31D16” }], hash: “0000ddb477024b0fb97c02e34bfad38eaee9891524759ba8801e06283b12cb9c”, nonce: “270778”, merkle: “713f5eb6109b03eb22cf8236171040f6bbf6171fbb2513b782b8b9fa9f41807f”, miner: “MTYwLjE2LjExNy44MA==”, validator: “MTYwLjE2LjExNy44MA==”, op: “” }

同じような容量で、gettransactionも同様に作ります。
$ ./target/debug/ruscal gettransaction 8A5216CD62C309A4923E9088CA9284AFC7C0261D89754FCE84735EC34A193A089B7A4C62FC32F91AE0B83549D575CE3D5EBAC1C4B9A61F0EF67D1B851F3F3E53

transactionの送信の場合

#[derive(Args)]
struct MoveArgs {
  pub_key: String,
  address: String,
  amount: i32
}

impl MoveArgs {
  fn run(&self) {
    // transaction送信関数を呼び出す
  }
}

$ ./target/debug/ruscal move de2ca55d5746f0e1bf8f1a1fbdb7634de5c1d5b4e49dc29bb78613fefb199d93eb8eb73545791a245c1f1ca6d5ce0 12sSVCmfi7kgsdG4ZmaargPppDRvkE5zvD 1000

なるほど、大分わかってきました。

【Ethereum】erc20とethをswap

pragma solidity ^0.8.0;

interface IERC20 {
    function transfer(address to, uint256 amount) external returns (bool);
    function transferFrom(address from, address to, uint256 amount) external returns (bool);
}

contract SimpleSwap {
    address public owner;
    IERC20 public token;
    uint256 public rate;

    constructor(address _tokenAddress, uint256 _rate) {
        owner = msg.sender;
        token = IERC20(_tokenAddress);
        rate = _rate;
    }

    receive() external payable {
        uint256 tokenAmount = msg.value * rate;
        require(token.transfer(msg.sender, tokenAmount), "Token transfer failed");
    }

    function swapTokenForETH(uint256 tokenAmount) external {
        uint256 ethAmount = tokenAmount / rate;
        require(address(this).balance >= ethAmount, "Not enough ETH in contract");

        require(token.transferFrom(msg.sender, address(this), tokenAmount), "Token transfer failed");

        (bool success, ) = msg.sender.call{value: ethAmount}("");
        require(success, "ETH transfer failed");
    }

    function withdrawETH() external {
        require(msg.sender == owner, "Not owner");
        payable(owner).transfer(address(this).balance);
    }

    function withdrawTokens() external {
        require(msg.sender == owner, "Not owner");
        uint256 balance = tokenBalance();
        require(token.transfer(owner, balance), "Token withdrawal failed");
    }

    function tokenBalance() public view returns (uint256) {
        return token.balanceOf(address(this));
    }
}

【Ethereum】送信者が特定の条件の元、ethを送金

sendではなく、recipient.callで送信してますね。

pragma solidity ^0.8.0;

constract ConditionTransfer {
    address public owner;
    address payable public recipient;
    uint256 public unlockTime;

    constructor(address payable _recipient, uint256 _unlockTime) {
        owner = msg.sender;
        recipient = _recipient;
        unlockTime = _unlockTime;
    }

    receive() external payable {}

    function release() external {
        require(msg.sender == owner, "Only owner can release funds");
        require(block.timestamp >= unlockTime, "Funds are locked");

        uint256 amount = address(this).balance;
        require(amount > 0, "No funds to send");

        (bool success, ) = recipient.call{value: amount}("");
        require(success, "Transfer failed");
    }
}

【Ethereum】トレーサビリティのsmart contractを考える

単純にアドレスに保存するだけであれば、mapping(address => Data) accounts;とすれば良さそう。
ただし、この場合は、商品ごとにアドレスを持っていないといけない。
緯度経度やstatusの管理は、フロントエンド側(React)で実装か…
memoryとstorageの仕様詳細が欲しいところ。。。

pragma solidity ^0.8.17;

contract Traceability {

    struct Data {
        uint256 id;
        string name;
        string latitude;
        string longitude;
        string status;
    }

    address[] public users;

    mapping(address => Data) accounts;

    function registerAccount(uint256 _id, string memory _name, string memory latitude, string memory longitude, string memory status)
        public 
        returns (bool)
    {
        accounts[msg.sender].id = _id;
        accounts[msg.sender].name = _name;
        accounts[msg.sender].latitude = latitude;
        accounts[msg.sender].longitude = longitude;
        accounts[msg.sender].status = status;
        
        users.push(msg.sender);
        return true;
    }

    function ViewAccount(address user) public view returns (uint256, string memory, string memory, string memory, string memory) {
        uint256 _id = accounts[user].id;
        string memory _name = accounts[user].name;
        string memory _latitude = accounts[user].latitude;
        string memory _longitude = accounts[user].longitude;
        string memory _status = accounts[user].status;

        return (_id, _name, _latitude, _longitude, _status);
    }

}

ethの受け取り

pragma solidity ^0.8.17;

contract RecvEther {
    address public sender;

    uint public recvEther;

    function () payable {
        sender = msg.sender;
        recvEther += msg.value;
    }
}

【Ethereum】solidity 基礎

memoryは処理中のみ保存し、storageは処理後、ブロックチェーンに保存される。

pragma solidity ^0.8.17;

contract Register {
    struct Data {
        string name;
        uint256 age;
        string hobby;
    }

    // 全ユーザのアドレスを保存
    address[] public users;

    mapping(address => Data) accounts;

    function registerAccount(string memory _name, uint256 _age, string memory _hobby) 
        public 
        returns (bool)
    {
        if (!isUserExist(msg.sender)) {
          users.push(msg.sender);
        }
        // msg.sender はトランザクション送信者
        accounts[msg.sender].name = _name;
        accounts[msg.sender].age = _age;
        accounts[msg.sender].hobby = _hobby;
        return true;
    }

    function isUserExist(address user) public view returns (bool) {
        for (uint256 i = 0; i < users.length; i++) {
            if (users[i] == user) {
                return true;
            }
        }
        return false;
    }

    function ViewAccount(address user) public view returns (string memory, uint256, string memory) {
        string memory _name = accounts[user].name;
        uint256 _age = accounts[user].age;
        string memory _hobby = accounts[user].hobby;

        return (_name, _age, _hobby);
    }
}

remixでデプロイのテストができる

metamaskアカウントでsepoliaにdeployする
https://sepolia.etherscan.io/

フロントエンド

import React from "react";
import Resister from "./Register.json";
import getWeb3 from "./getWeb3";
// import "./App.css";
class App extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      web3: null,
      accounts: null,
      contract: null,
      name: null,
      age: null,
      hobby: null,
      address: "",
      outputName: null,
      outputAge: null,
      outputHobby: null,
    };
  }

  componentDidMount = async () => {
    try {
      const web3 = await getWeb3();

      const accounts = await web3.eth.getAccounts();
      const networkId = await web3.eth.net.getId();
      const deployedNetwork = Resister.networks[networkId];
      const instance = new web3.eth.Contract(
        Resister.abi,
        deployedNetwork && deployedNetwork.address
      );

      this.setState({ web3, accounts, contract: instance });
    } catch (error) {
      alert(
        `Failed to load web3, accounts, or contract. Check console for details.`
      );
      console.error(error);
    }

    const { accounts } = this.state;
    console.log(accounts);
  };

  // アカウント情報の登録
  writeRecord = async () => {
    const { accounts, contract, name, age, hobby } = this.state;
    const result = await contract.methods.registerAccount(name, age, hobby).send({
      from: accounts[0],
    });
    console.log(result);

    if (result.status === true) {
      alert('会員登録が完了しました。');
    }
  };

  // アカウント情報の読み込み
  viewRecord = async () => {
    const { contract, accounts } = this.state;
    console.log(contract);

    const result = await contract.methods.viewAccount(accounts[0]).call();
    console.log(result);

    const outputName = result[0];
    const outputAge = result[1];
    const outputHobby = result[2];
    this.setState({ outputName, outputAge, outputHobby });
  };

  handleChange = (name) => (event) => {
    this.setState({ [name]: event.target.value });
  };

  render() {
    return (
      <div className="App">
        <br />
        <form>
          <div>
            <label>氏名:</label>
            <input
              onChange={this.handleChange("name")} />
          </div>

          <div>
            <label>年齢:</label>
            <input
              onChange={this.handleChange("age")} />
          </div>

          <div>
            <label>趣味:</label>
            <input
              onChange={this.handleChange("hobby")} />
          </div>

          <button type='button' onClick={this.writeRecord}>
            会員登録
          </button>
        </form>

        <br />
        <br />

        <form>
          <label>検索したいアドレスを入力してください。</label>
          <input onChange={this.handleChange("address")} />

          <button type='button' onClick={this.viewRecord}>
            検索
            </button>
        </form>

        <br />
        <br />

        {this.state.outputName ? <p>氏名: {this.state.outputName}</p> : <p></p>}
        {this.state.outputAge ? <p>年齢: {this.state.outputAge}</p> : <p></p>}
        {this.state.outputHobby ? <p>趣味: {this.state.outputHobby}</p> : <p></p>}

      </div>

    );
  }
}

export default App;

ちょっと記事が古いので期待通りに動かないが、

【Solana】Proof of HistoryをPythonで書く

前のブロックのiter,hashoutをベースに iter%(2**delay) == 0 になるまで、ブロックごとに262144回sha256を計算して、hash値を求める。hashoutが決まっているので、先回りしてブロックを作れそうだが、SolanaはPoSのため、不正がバレるとstakingが没収されてしまう。なるほどねー

import datetime
import hashlib
import time
import os
import pathlib
import random
import string
from random import randint

iter=1
hashin = ''.join(random.choices(string.ascii_uppercase + string.digits, k = 10))
hashout = hashlib.sha256(hashin.encode()).hexdigest()

print(hashin)
print(hashout)

def datastream():
    v1 = int(randint(1200, 1500))
    v2 = int(randint(1300, 1700))
    v3 = int(randint(1100, 1500))
    v4 = int(randint(4000, 5600))
    v5 = int(randint(4000, 5600))
    v6 = int(randint(1900, 2400))
    v7 = int(randint(1920, 2300))
    v8 = int(randint(1850, 2200))
    v9 = int(randint(1900, 2300))
    v10 = int(randint(1800, 2200))
    return [v1, v2, v3, v4, v5, v6, v7, v8, v9, v10];

class Block:
    blockNo = 0
    count = iter
    data = None
    next = None
    hash = "None"
    previous_hash = "None"
    timestamp = datetime.datetime.now()

    def __init__(self, data):
        self.data = datastream()

    def hash(self):
        file = pathlib.Path("TToken")
        if file.exists():
            tier=open("TToken").readline().rstrip()
        else:
            with open("benchmark.py") as infile:
                exec(infile.read())
            tier=open("TToken").readline().rstrip()

        if tier=="T1":
            h = hashlib.md5()
        elif tier=="T2":
            h = hashlib.sha1()
        elif tier=="T3":
            h = hashlib.blake2s()
        elif tier=="T4":
            h = hashlib.sha3_256()

        h.update(
		str(self.nonce).encode('utf-8') +
		str(self.data).encode('utf-8') +
		str(self.previous_hash).encode('utf-8') +
		str(self.timestamp).encode('utf-8') +
		str(self.blockNo).encode('utf-8')
		)
        return h.hexdigest()
    
        block.blockNo = self.block.blockNo + 1

    def __str__(self):
        return "Block Number: " + str(self.blockNo) + "\nHistory Count: " + str(self.count) + "\nBlock Data: " + str(self.data) + "\nBlock Hash: " + str(self.hash) + "\nPrevious Hash: " + str(self.previous_hash) + "\n--------------"

class Blockchain:
	block = Block("Genesis")
	dummy = head = block

	def add(self, block):
		if (self.block.blockNo ==0):
			block.previous_hash =  "Origin"
		else:
			block.previous_hash = self.block.hash
		block.blockNo = self.block.blockNo + 1

		self.block.next = block
		self.block = self.block.next

	def mine(self, block):
		global iter
		global hashin
		global hashout
		delay = 18
		cont = 1
		while(cont == 1):
			if int(iter%(2**delay) == 0):
				block.count = iter
				block.hash = hashout
				self.add(block)
				print(block)
				iter += 1
				hashin=hashout
				hashout = hashlib.sha256(hashin.encode()).hexdigest()
				cont = 0
				break
			else:
				iter += 1
				hashin=hashout
				hashout = hashlib.sha256(hashin.encode()).hexdigest()

t_initial = time.perf_counter()
blockchain = Blockchain()
b=int(input('Enter the number of Blocks for this simulation:'))

for n in range(b):
    blockchain.mine(Block(n+1))
t_final = time.perf_counter()
delta_t = t_final - t_initial
delta_unit = delta_t*1000/b
print("comutation Time per Block(ms):"+str(delta_unit))
input('Press ENTER to exit')

Enter the number of Blocks for this simulation:3
Block Number: 1
History Count: 262144
Block Data: [1297, 1642, 1372, 5138, 5301, 2188, 1998, 2150, 1914, 1862]
Block Hash: a53e39cef8be27ba38e73fe216fbfc2efc63bca056fa2a6a18380e9d93c98ea3
Previous Hash: Origin
————–
Block Number: 2
History Count: 524288
Block Data: [1211, 1633, 1307, 4757, 5133, 2206, 2032, 1891, 2257, 2139]
Block Hash: 79561ebd2627b432d1e619dee9db7ac85593a4357925827754b1faefd42c1b72
Previous Hash: a53e39cef8be27ba38e73fe216fbfc2efc63bca056fa2a6a18380e9d93c98ea3
————–
Block Number: 3
History Count: 786432
Block Data: [1459, 1682, 1131, 5339, 4983, 2057, 1948, 2192, 2017, 2076]
Block Hash: d33e10fa10273b5d64ccdad34ffcbaae7673cb785807c49f199b204a148e6cd9
Previous Hash: 79561ebd2627b432d1e619dee9db7ac85593a4357925827754b1faefd42c1b72
————–
comutation Time per Block(ms):795.6611973543962
Press ENTER to exit