Notice
Recent Posts
Recent Comments
Link
«   2024/07   »
1 2 3 4 5 6
7 8 9 10 11 12 13
14 15 16 17 18 19 20
21 22 23 24 25 26 27
28 29 30 31
Tags
more
Archives
Today
Total
관리 메뉴

개발공부일지

BlockChain - Transaction, UTXO(Unspent Transaction Output), jest 테스트하기 본문

BlockChain

BlockChain - Transaction, UTXO(Unspent Transaction Output), jest 테스트하기

보람- 2024. 1. 24. 15:19

 


목차

1. Transaction

2. UTXO(Unspent Transaction Output)

3. TEST하기


 

 

 

 

1. Transaction

- 자산을 전송하거나 기록하는 디지털 자산 전송
- 트랙잭션 입력 및 출력 (INPUT, OUTPUT) 있다.
   - 입력 INPUT : 이전 트랙잭션의 출력을 참조
   - 출력 OUTPUT : 자신이 받을 수 있는 주소와 양을 정의


- 트랜잭션 검증을 위해 서명(개인키로 서명하고) 공개키로 검증, 트랙잭션 승인
- 트랙잭션 풀에 담겨있는 트랜잭션을 블록에 기록한다.


- 블록 채굴을 하면 트랜잭션 처리가 되고 블록 생성 권한을 얻음( 마이닝 퀴즈 해결하면)
- 블록이 정상적으로 체인에 추가 되면 트랜잭션 처리됨
  → 이때 새로운 블록의 첫번째 트랜잭션이 코인베이스 트랜잭션
- 새로운 블록의 첫 거래이자 블록 채굴 보상!

 

 

 

 

2. UTXO(Unspent Transaction Output)

- 각 노드의 데이터 베이스 (객체안에 주소와 잔액이 있어 조회 가능)
- 객체 내용으로 트랜잭션 OUT 해시값과 소유자 주소, 잔액 내용 포함

- A ≫ B 1비트를 보냈다면 트랜잭션이 생성되고
  - txIn : 이전 트랜잭션에서 남은 잔액을 참조해서 송금하고 트랜잭션 검증하고,

             출력값이 처리가 되면 UTXO에 미사용 객체에 추가된다!
  - UTXO에는 트랜잭션 승인되면 사용한 객체를 삭제시키고
  - 새로운 객체가 들어감! (받은사람과 보낸 사람의 내용들 포함, 수정되는것이 아님!) 

 

 

 

 

3. jest로 테스트

 

1) 개인키 만들기

- 목적 : 공개키 생성과 서명 생성

- randomBytes를 사용하여 랜덤함 2진수를 구해서 privateKey 생성

 


2) 공개키 만들기
- 목적 : 개인키로 만든 서명을 검증하는 역할

- 타원곡선암호기술을 사용하여 publicKey 생성

import elliptic from 'elliptic';

const ec = new elliptic.ec('secp256k1');



3) 서명 만들기

- 만들어둔  privateKey와 트랜잭션 데이터의 hash값으로 서명을 만들기

 



4) 유효한 서명인지 공개키로 검증하기

- 트랜잭션 데이터의 hash값, 서명, publicKey을 넣어 true가 나오는지 검증하기

 


5) 지갑 주소 확인하기

- publicKey를 잘라(slice) 계정 확인하기

 

 

6) 트랜잭션 테스트하기

- 보내는 사람의 계정과 금액을 임의로 정하고 (예시 →  계정:address, 금액:40)

- 미사용 잔액 객체를 만들어 추가해주기

- 임시 트랜잭션 해시값을 구하기

- UTXO 객체 생성하기 (트랜잭션 Pool 확인해보기 → 거래 전으로 금액엔 40이 들어있음)

- 보내는 사람 서명으로 검증하기 (임의의 영수증 객체를 만들어서 → 상대방에서 10을 송금)

- 트랜잭션 pool 확인해보기 (10송금한 것과 잔액 30이 있는 2개의 객체가 존재함)

- 처리된 트랜잭션 삭제하고 확인해보기 (트랜잭션 pool 비어있음)


 

** test 코드 

더보기
import elliptic from 'elliptic';
import Transaction from '@core/transaction/transaction';
import Unspent from '@core/transaction/unspent';
import { randomBytes } from 'node:crypto';
import { SHA256 } from 'crypto-js';
import { Receipt } from '@core/transaction/interface/receipt.interface';

const ec = new elliptic.ec('secp256k1');

describe('Transaction', () => {
  let transaction: Transaction;
  let unspent: Unspent;
  let privateKey: string;
  let publicKey: string;
  let signature: elliptic.ec.Signature;
  let address;

  // 테스트 케이스가 실행되기 전에 호출되는 함수!
  beforeEach(() => {
    transaction = new Transaction();
    unspent = new Unspent();
  });

  it('개인키 생성하기', () => {
    // 랜덤한 2진수를 구하기
    privateKey = randomBytes(32).toString('hex');
    console.log('개인키 길이 :', privateKey.length);
    console.log('개인키 :', privateKey);
  });

  it('공개키 생성하기', () => {
    const keyPair = ec.keyFromPrivate(privateKey);
    publicKey = keyPair.getPublic().encode('hex', true);
    console.log('공개키 길이 :', publicKey.length);
    console.log('공개키:', publicKey);
  });

  it('서명 만들기', () => {
    const keyPair = ec.keyFromPrivate(privateKey);
    const hash = SHA256('transaction data 01').toString();
    signature = keyPair.sign(hash, 'hex');
    console.log('서명 :', signature); // true
  });

  it('공개키로 서명 검증하기', () => {
    const hash = SHA256('transaction data 01').toString();
    const verify = ec.verify(
      hash,
      signature,
      ec.keyFromPublic(publicKey, 'hex')
    );
    console.log('검증 : ', verify);
  });

  it('지갑주소 확인하기', () => {
    address = publicKey.slice(26).toString();
    console.log(`계정 : 0x${address}`);
  });

  it('트랜잭션 테스트하기', () => {
    // 보내는 사람의 계정 주소 임의로 만들기 (0 40개)
    const account = '0'.repeat(40);

    // 보내는 사람의 금액 임의로 만들기
    const amount = 40;

    // 미사용 잔액 객체 만들어 추가하기
    const txout = transaction.createTxOut(address, amount);
    // account:addres // amount:40

    // 임시 트랜잭션 해시값
    const txHash = SHA256('tx01').toString();

    // UTXO 객체 추가
    const unspentOuts = unspent.create(txHash);
    unspentOuts(txout, 1); // 임의의 index값으로 1 주기

    console.log('unspent 미사용 객체 추가 : ', unspent.getUnspentTxPool());

    // 송금한사람 서명으로 검증하기
    const receipt: Receipt = {
      sender: address,
      received: account,
      amount: 10,
      signature: signature,
    };
    const tx01 = transaction.create(receipt, unspent.getUTXO(address));
    console.log('트랜잭션 pool : ', transaction.getPool());

    // 트랜잭션 처리
    unspent.update(tx01);
    transaction.update(tx01);

    console.log(
      'unspent 미사용객체 제거 및 새로운 객체 추가 :',
      unspent.getUnspentTxPool()
    );
    console.log('처리된 트랜잭션 pool 제거 :', transaction.getPool());
  });
});

 

 

 


※ 용어 개념 이해하기