C++のメモリの扱い

C言語はメモリ確保関数だったが、C++は命令で確保する

### メモリ確保/解放命令
– new
メモリを確保する命令
確保できない場合はstd::bad_allocを投げる
std::nothrowを指定すると、例外ではなくnullptrを返す

– delete
newで確保した領域を解放する命令

– delete[]
newで確保した領域を解放する命令

# include <memory>

int main() {
    // 通常の確保
    char* p = new char[100];

    char* p2 = nullptr;
    try {
        p2 = new char[100];
    } catch (const std::bad_alloc& e) {

    }

    char* p3 = new(std::nothrow) char[100];
    if (p3 == nullptr) {
    }

    // 指定した領域からメモリを確保する
    char buf[100];
    char* p4 = new (buf) char[100];

    int* n = new int;
    int* n2 = new int();

    int* n3 = new int(10);

    delete n3;
    delete n2;
    delete n;

    delete[] p3;
    delete[] p2;
    delete[] p;

}
#include <iostream>

int main() {
    
    int* p = new int;
    *p = 77;
    std::cout << *p << std::endl;

    delete p;
}

### 配列の確保

#include <iostream>

int main() {
    
    int* arr = new int[5];
    
    for (int i = 0; i < 5; ++i)
        arr[i] = i * 10;

    for (int i = 0; i < 5; ++i)
        std::cout << arr[i] << " ";

    delete[] arr;
    return 0;
}

$ ./test
0 10 20 30 40

### スマートポインタ

#include <iostream>
#include <memory>

class Sample {
public:
    void greet() {
        std::cout << "Hello from Sample!\n";
    }
};

int main() {
    
    std::unique_ptr<Sample> ptr = std::make_unique<Sample>();
    ptr->greet();

    return 0;
}

C言語のメモリの扱い

### メモリ管理の概要
1. メモリ確保
2. メモリ解放
の順番で制御する

– メモリリーク
確保したメモリを不要になっても解放せずにいると、結果としてメモリ不足となって確保できなくなる

### メモリ確保・解放関数
– malloc
指定されたサイズのメモリを確保する
確保できない場合はNullを返す

– calloc
指定されたサイズのメモリブロックを確保し、確保した領域を0クリアする
確保できない場合はNullを返す

– realloc
確保済みのメモリを拡張する
確保できない場合はNullを返す

– free
malloc, calloc, reallocで確保した領域を解放する関数

# include <stdlib.h>

int main(void) {

    printf("Practice C  Memory Programming!! \n");

    // 100 byteのメモリ確保
    char* p = malloc(100);
    if (p == NULL) {
        // 確保できなかった時の処理
    }

    int* p2 = calloc(100, sizeof(int));
    if (p2 == NULL){}

    char* p3 = realloc(p, 200);
    if (p3 == NULL) {
    } else {
        p = p3;
    }

    free(p2);
    free(p);

    return 0;
}
#include <stdio.h>
#include <stdlib.h>

int main() {

    printf("Practice C  Memory Programming!! \n");

    int *p;

    p = (int *)malloc(sizeof(int));

    if (p == NULL) {
        printf("メモリの確保に失敗しました\n");
        return 1;
    }

    *p = 55;
    printf("pが指す値: %d\n", *p);

    free(p);

    return 0;
}

$ ./test
Practice C Memory Programming!!
pが指す値: 55

配列の場合

#include <stdio.h>
#include <stdlib.h>

int main() {

    printf("Practice C  Memory Programming!! \n");

    int *arr;
    int n = 5;

    arr = (int *)malloc(n * sizeof(int));

    if (arr == NULL) {
        printf("メモリの確保に失敗しました\n");
        return 1;
    }

    for (int i = 0; i < n; i++){
        arr[i] = i * 10;
    }

    for (int i = 0; i < n; i++) {
        printf("arr[%d] = %d\n", i, arr[i]);
    }

    free(arr);

    return 0;
}

$ ./test
Practice C Memory Programming!!
arr[0] = 0
arr[1] = 10
arr[2] = 20
arr[3] = 30
arr[4] = 40

ipfsの利用

### ローカル環境でのipfs
$ echo “version 1 of my text” > mytextfile.txt
$ cat mytextfile.txt
version 1 of my text
$ ipfs cat QmZtmD2qt6fJot32nabSP3CUjicnypEBz7bHVDhPQt9aAy
version 1 of my text

これをipfsネットワークで実行したい

### ipfsに接続
# ipfs daemon
別のターミナルで以下を実行
# ipfs swarm peers |head
/ip4/103.253.72.2/tcp/4001/p2p/12D3KooWMGNgfvPVhUdzWfGifHMkVvJ991EQCCEWXTREc8CPHui7
/ip4/104.244.76.218/tcp/4001/p2p/12D3KooWMbUuHSEvy4KNnkW8H9m63zesuuvVNS25hTL1SQtRh835
/ip4/109.123.240.146/tcp/4001/p2p/12D3KooWPzJcDSFQrBSgrdPbSAwTX5x6aWKWAoAzuEj3NBb43iKD
/ip4/109.203.194.197/tcp/56881/p2p/12D3KooWMgRnDE2oPkd72ZVb3pw4Pww9F24nVfCPj18gB1ARhUCt
/ip4/112.25.240.107/tcp/4001/p2p/12D3KooWHkTtvW6qCR9yATp6g8EC6hHRZGEiybyLQqmsRwoJ7Ac2
/ip4/113.89.245.184/tcp/15088/p2p/12D3KooWD8U6239pcaHdYqrg175DwM9EvFxLMuWo5PjzHd7bLZ15
/ip4/115.204.117.91/tcp/35129/p2p/12D3KooWGknnwvTJwjzYHpXgYU5K6fF2P9d8wtT3zBYudwnA7XmZ
/ip4/117.26.88.117/tcp/51698/p2p/QmQGeMkzJmkWum4FQwxvx6QPTvuNTsGoXBXeCxsWMrHg31
/ip4/136.243.46.54/tcp/4001/p2p/12D3KooWMahkHusnsTbMGVnCyXmKyLyifD8VnpMiH4hKNn6wqPfb
/ip4/136.244.116.199/tcp/4001/p2p/12D3KooWCXC9dBZZsA6E2jJh8SoyGCsGbFSLQtBquthoQpqjgpKp

ubuntuにipfsのインストール

$ wget https://dist.ipfs.io/go-ipfs/v0.5.0/go-ipfs_v0.5.0_linux-arm64.tar.gz
$ tar xvzf go-ipfs_v0.5.0_linux-arm64.tar.gz
$ cd go-ipfs/
$ sudo ./install.sh
Moved ./ipfs to /usr/local/bin
$ ipfs version
ipfs version 0.5.0
$ ipfs init
initializing IPFS node at /home/vagrant/.ipfs
generating 2048-bit RSA keypair…done
peer identity: QmWKa24RSJMHNZNSWiB5FuUkLQFvkM7L8ZqhmUKaUbLAJF
to get started, enter:

ipfs cat /ipfs/QmQPeNsJPyVWPFDVHb77w8G42Fvo15z4bG2X8D2GhfbSXc/readme
$ ipfs cat /ipfs/QmQPeNsJPyVWPFDVHb77w8G42Fvo15z4bG2X8D2GhfbSXc/readme
Hello and Welcome to IPFS!

██╗██████╗ ███████╗███████╗
██║██╔══██╗██╔════╝██╔════╝
██║██████╔╝█████╗ ███████╗
██║██╔═══╝ ██╔══╝ ╚════██║
██║██║ ██║ ███████║
╚═╝╚═╝ ╚═╝ ╚══════╝

If you’re seeing this, you have successfully installed
IPFS and are now interfacing with the ipfs merkledag!

——————————————————-
| Warning: |
| This is alpha software. Use at your own discretion! |
| Much is missing or lacking polish. There are bugs. |
| Not yet secure. Read the security notes for more. |
——————————————————-

Check out some of the other files in this directory:

./about
./help
./quick-start <-- usage examples ./readme <-- this file ./security-notes $ ls ~/.ipfs blocks config datastore datastore_spec keystore version

【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

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

【Rust】getnewaddressのAPI機能を作る

### コマンドライン引数の書き方

fn main() {

   let command_name = std::env::args().nth(0).unwrap_or("CLI".to_string());
   let name = std::env::args().nth(1).unwrap_or("World".to_string());

   println!("Hello {} via {}!", name, command_name);
}

$ cargo run
Finished `dev` profile [unoptimized + debuginfo] target(s) in 0.04s
Running `target/debug/ruscal`
Hello World via target/debug/ruscal!

### 上記を応用する

fn main() {
   let args = App::parse();
   match args.command {
    Command::Getnewaddress => getnewaddress(),
   }
}

fn getnewaddress() {
  address::get_address();
}
use p256::{
    ecdsa::{SigningKey},
    pkcs8::EncodePrivateKey, PublicKey,SecretKey};
use rand_core::{OsRng};
use std::{fs::File, io::Write, path::Path};
use ripemd::{Ripemd160};
use sha2::{Digest, Sha256};

pub fn get_address() {
    init_secret();
    let contents = std::fs::read_to_string("./config/tmp.pem")
        .expect("something went wrong reading the file");
    let secret_pem = contents.trim();

    let secret_key = secret_pem.parse::<SecretKey>().unwrap();
    let _private_key_serialized = hex::encode(&secret_key.to_bytes());

    let public_key = secret_key.public_key();
    let _public_key_serialized = hex::encode(&public_key.to_sec1_bytes());
    let address = create_address(&public_key);  
    println!("{}", address);
}

pub fn init_secret() {
    let path = Path::new("./config/tmp.pem");
    if path.is_file() {
        // println!("The private key, public key, and address have already been created.");
    } else {
        let secret_key = SigningKey::random(&mut OsRng);
        let secret_key_serialized = secret_key
            .to_pkcs8_pem(Default::default())
            .unwrap()
            .to_string();
        let mut file = File::create("./config/tmp.pem").expect("file not found.");
        writeln!(file, "{}", secret_key_serialized).expect("can not write.");
        println!("created a private key.");
    }
}

pub fn create_address(public_key: &PublicKey) -> String {

    let vk = public_key.to_sec1_bytes();
    let mut hasher = Sha256::new();
    hasher.update(vk);
    let hashed_sha256 = hasher.finalize();

    let mut hasher = Ripemd160::new();
    hasher.update(hashed_sha256);
    let account_id = hasher.finalize();

    let mut payload = account_id.to_vec();
    payload.insert(0, 0x00);

    let mut hasher = Sha256::new();
    hasher.update(&payload);
    let hash = hasher.finalize();

    let mut hasher = Sha256::new();
    hasher.update(hash);
    let checksum = hasher.finalize();

    payload.append(&mut checksum[0..4].to_vec());

    const ALPHABET: &str = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz";
    let address = base_x::encode(ALPHABET, &payload);

    return address;
}

$ cargo run getnewaddress
Compiling ruscal v0.1.0 (/home/vagrant/dev/rust/api)
Finished `dev` profile [unoptimized + debuginfo] target(s) in 0.92s
Running `target/debug/ruscal getnewaddress`
1BnpTXdSbSgMZwWYq7cdU3LPSw1g4YhyHZ

【IPFS】Merkle DAGをPythonで書く

import hashlib

class Node:
    def __init__(self, data=None, children=None):
        self.data = data
        self.children = children or []
        self.hash = self.compute_hash()

    def compute_hash(self):
        m = hashlib.sha256()
        if self.data:
            m.update(self.data.encode('utf-8'))
        for child in self.children:
            m.update(child.hash.encode('utf-8'))
        return m.hexdigest()

    def __repr__(self):
        return f"Node(hash={self.hash[:10]}, data={self.data})"

# ノードを作成
leaf1 = Node(data="block A")
leaf2 = Node(data="block B")
leaf3 = Node(data="block C")

# 同じ子を共有するノード
intermediate1 = Node(children=[leaf1, leaf2])
intermediate2 = Node(children=[leaf2, leaf3])

# DAGのルート
root = Node(children=[intermediate1, intermediate2])

# 表示
print("Merkle DAG:")
print("Root:", root)

$ python3 merkledag.py
Merkle DAG:
Root: Node(hash=b7026ffa9b, data=None)

同じハッシュを持つノードを共有
leaf2 は2つの親ノードに共有されており、DAGならでは構造となっている。IPFSやGitで使われる構造

【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");
    }
}

【Python】kecchak256

kecchak256は、文字列をランダムな256ビットの16進数にマッピングする機能
ethereumで使用されている

$ pip3 install pysha3

import sha3

data = b'Hello, keccak256!'

keccak = sha3.keccak_256()
keccak.update(data)
hash_hex = keccak.hexdigest()

print("keccak256 hash:", hash_hex)

$ python3 keccak256.py
keccak256 hash: 0fa5c2f72a50589fff02f2f5105ba40d97c01e114df6fd00cc4b1fc0afbec43a