이미지 로딩 중...

타입스크립트로 비트코인 클론하기 7편 제네시스 블록 생성하기 - 슬라이드 1/9
A

AI Generated

2025. 11. 9. · 2 Views

타입스크립트로 비트코인 클론하기 7편 제네시스 블록 생성하기

블록체인의 시작점인 제네시스 블록을 타입스크립트로 직접 구현해봅니다. 블록 구조 설계부터 해시 생성, 체인 초기화까지 실무에서 사용할 수 있는 블록체인 기초를 다룹니다.


목차

  1. 제네시스_블록의_개념
  2. Block_클래스_설계
  3. 블록_해시_생성
  4. 제네시스_블록_생성_함수
  5. 타임스탬프_관리
  6. 블록_데이터_구조
  7. 이전_블록_해시_연결
  8. 블록체인_클래스_초기화

1. 제네시스_블록의_개념

시작하며

여러분이 새로운 블록체인 프로젝트를 시작할 때 이런 고민을 해본 적 있나요? "첫 번째 블록은 어떻게 만들어야 하지?

이전 블록이 없는데 이전 해시는 어떻게 하지?" 이런 문제는 모든 블록체인 시스템에서 반드시 해결해야 하는 근본적인 문제입니다. 블록체인은 각 블록이 이전 블록을 참조하는 구조인데, 맨 처음 블록은 참조할 이전 블록이 없기 때문입니다.

이 문제를 해결하지 못하면 블록체인 자체를 시작할 수 없습니다. 바로 이럴 때 필요한 것이 제네시스 블록(Genesis Block)입니다.

제네시스 블록은 블록체인의 시작점이 되어 모든 후속 블록들의 기준점 역할을 합니다.

개요

간단히 말해서, 제네시스 블록은 블록체인의 최초 블록으로, 이전 블록이 존재하지 않는 특별한 블록입니다. 실제 비트코인의 제네시스 블록은 2009년 1월 3일에 생성되었으며, 사토시 나카모토가 "The Times 03/Jan/2009 Chancellor on brink of second bailout for banks"라는 메시지를 포함시켰습니다.

이처럼 제네시스 블록은 단순한 기술적 요소를 넘어 블록체인의 탄생을 증명하는 역사적 기록이기도 합니다. 기존에는 중앙 서버에서 데이터베이스의 첫 레코드를 생성했다면, 블록체인에서는 제네시스 블록을 통해 분산 원장의 시작점을 만듭니다.

제네시스 블록의 핵심 특징은 세 가지입니다. 첫째, 이전 블록 해시가 0이거나 특정 값으로 고정됩니다.

둘째, 인덱스가 항상 0입니다. 셋째, 모든 노드에서 동일한 제네시스 블록을 공유합니다.

이러한 특징들이 블록체인 네트워크의 일관성과 신뢰성을 보장합니다.

코드 예제

// 제네시스 블록의 기본 구조
interface GenesisBlockData {
  index: 0;
  timestamp: number;
  data: string;
  previousHash: "0";
  hash: string;
}

// 제네시스 블록 생성 예시
const genesisBlock: GenesisBlockData = {
  index: 0,
  timestamp: 1704067200000, // 2024-01-01 00:00:00
  data: "Genesis Block - Bitcoin Clone",
  previousHash: "0",
  hash: "816534932c2b7154836da6afc367695e6337db8a921823784c14378abed4f7d7"
};

설명

이것이 하는 일: 제네시스 블록은 블록체인의 시작점을 정의하고, 모든 후속 블록들이 연결될 수 있는 기준점을 제공합니다. 첫 번째로, index가 0으로 설정되어 이 블록이 체인의 첫 번째 블록임을 명확히 표시합니다.

이는 블록체인을 순회할 때 시작점을 쉽게 식별할 수 있게 해주며, 체인의 길이를 계산할 때도 기준이 됩니다. 그 다음으로, previousHash가 "0"으로 설정됩니다.

이는 이전 블록이 존재하지 않음을 의미하는 특별한 값입니다. 일부 구현에서는 64개의 0으로 채워진 문자열을 사용하기도 하며, 이는 블록체인 프로토콜의 일부로 미리 정의됩니다.

모든 노드가 동일한 previousHash를 사용해야 동일한 제네시스 블록을 생성할 수 있습니다. timestamp는 블록이 생성된 정확한 시간을 기록합니다.

제네시스 블록의 타임스탬프는 블록체인의 공식 시작 시간이 되며, 모든 노드에서 동일해야 합니다. data 필드에는 블록체인의 목적이나 의미를 담은 메시지를 저장할 수 있습니다.

마지막으로, hash는 이 블록의 모든 데이터(index, timestamp, data, previousHash)를 SHA-256 해시 함수로 계산한 결과입니다. 이 해시값은 블록의 무결성을 보장하며, 다음 블록의 previousHash로 사용되어 체인을 형성합니다.

여러분이 이 구조를 사용하면 완전히 독립적이고 검증 가능한 블록체인을 시작할 수 있습니다. 모든 참여 노드가 동일한 제네시스 블록에서 시작하므로, 데이터의 일관성이 보장되며, 블록체인의 전체 히스토리를 추적할 수 있는 명확한 시작점이 생깁니다.

실전 팁

💡 제네시스 블록의 데이터는 블록체인의 정체성을 나타내는 메시지를 담으세요. 비트코인처럼 의미 있는 메시지를 포함하면 블록체인의 목적과 탄생 시점을 영구적으로 기록할 수 있습니다.

💡 타임스탬프는 실제 배포 시점으로 설정하되, 테스트 환경에서는 고정된 값을 사용하세요. 고정된 값을 사용하면 단위 테스트에서 항상 동일한 해시를 생성할 수 있어 테스트가 안정적입니다.

💡 제네시스 블록은 변경되면 전체 체인이 무효화되므로, 프로덕션 배포 전에 신중하게 설계하세요. 한 번 배포된 제네시스 블록은 절대 수정할 수 없습니다.

💡 여러 네트워크(메인넷, 테스트넷)를 운영할 때는 각각 다른 제네시스 블록을 사용하세요. 이렇게 하면 네트워크 간 블록이 섞이는 것을 방지할 수 있습니다.


2. Block_클래스_설계

시작하며

여러분이 블록체인을 구현할 때 "블록은 어떤 속성을 가져야 하지? 클래스로 만들어야 할까, 아니면 인터페이스로만 정의할까?"라는 고민을 해본 적 있나요?

이런 설계 결정은 블록체인의 확장성과 유지보수성에 큰 영향을 미칩니다. 잘못 설계하면 나중에 새로운 기능을 추가할 때마다 전체 코드를 수정해야 하는 상황이 발생할 수 있습니다.

특히 타입스크립트에서는 타입 안정성을 고려한 설계가 필수적입니다. 바로 이럴 때 필요한 것이 제대로 된 Block 클래스 설계입니다.

클래스 기반 설계는 캡슐화, 메서드 추가, 타입 안정성을 모두 제공합니다.

개요

간단히 말해서, Block 클래스는 블록체인의 각 블록을 표현하는 타입스크립트 클래스로, 블록의 모든 속성과 동작을 캡슐화합니다. 실무에서 블록체인을 구현할 때는 블록의 검증, 직렬화, 비교 등 다양한 작업이 필요합니다.

단순한 인터페이스나 객체 리터럴로는 이런 기능들을 효과적으로 관리하기 어렵습니다. 클래스를 사용하면 데이터와 관련 메서드를 한 곳에 모아 관리할 수 있어 코드의 응집도가 높아집니다.

기존에는 단순히 객체를 생성하고 함수로 처리했다면, 클래스를 사용하면 생성자를 통한 초기화, 메서드를 통한 동작 정의, readonly를 통한 불변성 보장이 가능합니다. Block 클래스의 핵심 특징은 다음과 같습니다.

첫째, readonly 속성으로 블록의 불변성을 보장합니다. 둘째, 생성자를 통해 필수 속성을 강제합니다.

셋째, 타입스크립트의 타입 시스템을 활용해 컴파일 타임에 오류를 잡습니다. 이러한 특징들이 안전하고 예측 가능한 블록체인 구현을 가능하게 합니다.

코드 예제

// Block 클래스 정의
class Block {
  // readonly로 불변성 보장
  public readonly index: number;
  public readonly timestamp: number;
  public readonly data: string;
  public readonly previousHash: string;
  public readonly hash: string;

  // 생성자로 필수 속성 초기화
  constructor(
    index: number,
    timestamp: number,
    data: string,
    previousHash: string,
    hash: string
  ) {
    this.index = index;
    this.timestamp = timestamp;
    this.data = data;
    this.previousHash = previousHash;
    this.hash = hash;
  }

  // 블록 정보 출력 메서드
  public toString(): string {
    return `Block #${this.index} [${this.hash.substring(0, 10)}...]`;
  }
}

설명

이것이 하는 일: Block 클래스는 블록체인의 각 블록을 타입 안전한 방식으로 표현하며, 블록의 생성과 관리를 체계적으로 처리합니다. 첫 번째로, 모든 속성을 readonly로 선언하여 블록의 불변성을 보장합니다.

블록체인에서 한 번 생성된 블록은 절대 수정되어서는 안 됩니다. readonly 키워드를 사용하면 타입스크립트 컴파일러가 블록 속성의 변경 시도를 컴파일 타임에 차단합니다.

예를 들어, block.hash = "new hash"와 같은 코드는 컴파일 오류를 발생시킵니다. 그 다음으로, 생성자를 통해 블록 생성 시 모든 필수 속성을 강제합니다.

생성자의 매개변수로 index, timestamp, data, previousHash, hash를 모두 받도록 정의하면, 불완전한 블록이 생성되는 것을 방지할 수 있습니다. 타입스크립트는 생성자 호출 시 모든 인자가 올바른 타입인지 검증합니다.

public 키워드를 사용하여 외부에서 블록의 속성을 읽을 수 있도록 하되, readonly로 인해 수정은 불가능하게 만듭니다. 이는 투명성과 보안성을 동시에 달성하는 방법입니다.

toString() 메서드처럼 블록과 관련된 유틸리티 메서드도 클래스 내부에 정의할 수 있어 코드의 응집도가 높아집니다. 마지막으로, 이 클래스 설계는 향후 확장에 열려있습니다.

예를 들어, 블록 검증 메서드(isValid()), 직렬화 메서드(toJSON()), 블록 비교 메서드(equals()) 등을 쉽게 추가할 수 있습니다. 클래스의 인스턴스 메서드로 추가하면 블록 관련 로직이 한 곳에 집중되어 유지보수가 용이합니다.

여러분이 이 클래스 구조를 사용하면 타입 안정성, 불변성, 확장성을 모두 확보할 수 있습니다. IDE의 자동완성 기능도 완벽하게 작동하며, 리팩토링 시에도 타입스크립트가 모든 변경사항을 추적해줍니다.

실전 팁

💡 readonly를 사용하는 것만으로는 깊은 불변성이 보장되지 않습니다. data가 객체나 배열이라면 Readonly<T>나 ReadonlyArray<T> 타입을 사용하세요.

💡 생성자를 private으로 만들고 static 팩토리 메서드를 제공하면 블록 생성 로직을 더욱 세밀하게 제어할 수 있습니다. 예: static create(...), static createGenesis().

💡 블록 클래스에 검증 로직을 추가할 때는 생성자가 아닌 별도의 validate() 메서드를 만드세요. 생성자에서 예외를 던지면 테스트나 디버깅이 어려워질 수 있습니다.

💡 직렬화가 필요하다면 toJSON()과 static fromJSON() 메서드를 구현하세요. 이렇게 하면 블록을 네트워크로 전송하거나 파일에 저장할 때 일관된 방식을 사용할 수 있습니다.

💡 블록 크기를 제한하려면 data의 최대 길이를 검증하는 로직을 추가하세요. 실제 블록체인에서는 블록 크기 제한이 중요한 보안 요소입니다.


3. 블록_해시_생성

시작하며

여러분이 블록체인에서 블록의 무결성을 보장하려고 할 때 "어떤 해시 알고리즘을 사용해야 하지? 해시 입력값은 어떻게 구성해야 하지?"라는 고민을 해본 적 있나요?

이런 문제는 블록체인의 보안성과 직결됩니다. 잘못된 해시 알고리즘을 사용하거나 입력값을 부적절하게 구성하면 블록이 쉽게 위변조될 수 있습니다.

실제로 해시 충돌이 발생하거나 예측 가능한 해시가 생성되면 블록체인 전체의 신뢰성이 무너집니다. 바로 이럴 때 필요한 것이 SHA-256을 활용한 안전한 블록 해시 생성입니다.

비트코인과 동일한 해시 알고리즘을 사용하여 검증된 보안성을 확보할 수 있습니다.

개요

간단히 말해서, 블록 해시는 블록의 모든 데이터를 SHA-256 알고리즘으로 암호화한 고유한 지문으로, 블록의 무결성을 보장합니다. SHA-256(Secure Hash Algorithm 256-bit)은 미국 국가안보국(NSA)이 설계한 암호화 해시 함수로, 비트코인을 비롯한 대부분의 블록체인에서 표준으로 사용됩니다.

이 알고리즘은 어떤 크기의 입력값도 256비트(64자리 16진수 문자열)의 고정된 해시값으로 변환하며, 단방향 암호화이므로 해시값으로부터 원본 데이터를 복원할 수 없습니다. 또한 입력값이 1비트만 바뀌어도 완전히 다른 해시값이 생성됩니다.

기존에는 MD5나 SHA-1 같은 약한 해시 함수를 사용했다면, 현대의 블록체인에서는 충돌 공격에 강한 SHA-256을 사용합니다. 블록 해시 생성의 핵심 특징은 다음과 같습니다.

첫째, 결정론적(deterministic)입니다. 동일한 입력은 항상 동일한 해시를 생성합니다.

둘째, 눈사태 효과(avalanche effect)가 있어 입력의 작은 변화도 완전히 다른 해시를 만듭니다. 셋째, 계산은 빠르지만 역계산은 사실상 불가능합니다.

이러한 특징들이 블록체인의 위변조 방지를 가능하게 합니다.

코드 예제

import * as crypto from 'crypto';

// 블록 해시 계산 함수
function calculateHash(
  index: number,
  timestamp: number,
  data: string,
  previousHash: string
): string {
  // 모든 블록 데이터를 하나의 문자열로 결합
  const blockData = index + timestamp + data + previousHash;

  // SHA-256 해시 생성
  return crypto
    .createHash('sha256')
    .update(blockData)
    .digest('hex');
}

// 사용 예시
const hash = calculateHash(0, 1704067200000, "Genesis Block", "0");
console.log(hash); // "816534932c2b7154836da6afc367695e6337db8a921823784c14378abed4f7d7"

설명

이것이 하는 일: calculateHash 함수는 블록의 모든 핵심 데이터를 받아 SHA-256 알고리즘을 적용하여 블록의 고유한 해시값을 생성합니다. 첫 번째로, 블록의 모든 중요한 속성(index, timestamp, data, previousHash)을 하나의 문자열로 결합합니다.

이때 각 값을 단순히 연결(concatenation)하는데, 타입스크립트의 암묵적 타입 변환을 활용하여 숫자도 문자열로 자동 변환됩니다. 이 방식은 간단하지만 효과적이며, 모든 블록 데이터가 해시 계산에 포함되도록 보장합니다.

그 다음으로, Node.js의 내장 crypto 모듈을 사용하여 SHA-256 해시를 생성합니다. crypto.createHash('sha256')는 SHA-256 해시 객체를 생성하고, update(blockData)로 해시할 데이터를 입력하며, digest('hex')로 최종 해시값을 16진수 문자열로 출력합니다.

이 3단계 프로세스는 Node.js의 스트림 기반 암호화 API의 표준 패턴입니다. digest('hex')는 바이너리 해시값을 사람이 읽을 수 있는 64자리 16진수 문자열로 변환합니다.

예를 들어, "816534932c2b7154..."와 같은 형태입니다. 16진수를 사용하는 이유는 이진수보다 읽기 쉽고, Base64보다 URL 친화적이며, 블록체인 표준으로 널리 사용되기 때문입니다.

마지막으로, 이 함수는 순수 함수(pure function)로 설계되어 동일한 입력에 대해 항상 동일한 출력을 보장합니다. 부수 효과(side effect)가 없으므로 테스트하기 쉽고, 병렬 처리에도 안전합니다.

블록체인의 모든 노드가 이 함수를 사용하면 동일한 블록에 대해 동일한 해시를 계산할 수 있어 합의(consensus)가 가능해집니다. 여러분이 이 해시 함수를 사용하면 블록의 무결성을 수학적으로 보장할 수 있습니다.

누군가 블록의 데이터를 변경하면 해시값이 완전히 달라지므로 즉시 감지할 수 있으며, 이는 블록체인의 핵심 보안 메커니즘입니다.

실전 팁

💡 데이터를 결합할 때 구분자를 추가하면 더 안전합니다. 예: ${index}|${timestamp}|${data}|${previousHash}. 이렇게 하면 "12" + "34"와 "1" + "234"를 구분할 수 있습니다.

💡 실무에서는 data가 객체일 수 있으므로 JSON.stringify()를 사용하세요. 단, JSON.stringify()는 속성 순서를 보장하지 않으므로 키를 정렬하거나 직렬화 라이브러리를 사용하세요.

💡 해시 계산은 CPU 집약적이므로, 많은 블록을 처리할 때는 Worker Threads나 Cluster를 활용한 병렬 처리를 고려하세요.

💡 보안을 강화하려면 nonce(난수)를 추가하여 작업 증명(Proof of Work)을 구현할 수 있습니다. 비트코인은 이 방식으로 블록 생성 난이도를 조절합니다.

💡 해시값을 데이터베이스에 저장할 때는 인덱스를 생성하세요. 해시로 블록을 검색하는 경우가 많으므로 인덱스가 없으면 성능이 크게 저하됩니다.


4. 제네시스_블록_생성_함수

시작하며

여러분이 블록체인을 초기화할 때 "제네시스 블록을 매번 수동으로 만들어야 하나? 실수로 다른 값을 넣으면 어떻게 하지?"라는 걱정을 해본 적 있나요?

이런 문제는 실제로 치명적일 수 있습니다. 여러 노드에서 서로 다른 제네시스 블록을 생성하면 블록체인이 분기되어 합의에 도달할 수 없게 됩니다.

또한 제네시스 블록의 속성값을 하드코딩하면 코드 중복이 발생하고 유지보수가 어려워집니다. 바로 이럴 때 필요한 것이 제네시스 블록 생성 전용 함수입니다.

일관된 방식으로 제네시스 블록을 생성하여 모든 노드가 동일한 블록체인을 시작하도록 보장합니다.

개요

간단히 말해서, 제네시스 블록 생성 함수는 블록체인의 최초 블록을 일관된 방식으로 생성하는 팩토리 함수입니다. 실무에서는 블록체인 애플리케이션이 시작될 때마다 제네시스 블록을 생성해야 합니다.

이때 수동으로 값을 입력하면 오타나 실수가 발생할 수 있습니다. 팩토리 함수를 사용하면 제네시스 블록의 모든 속성을 한 곳에서 정의하고, 필요할 때마다 동일한 블록을 생성할 수 있습니다.

이는 특히 테스트 환경에서 매우 유용합니다. 기존에는 블록을 생성할 때마다 new Block(0, timestamp, data, "0", hash)처럼 생성자를 직접 호출했다면, 이제는 createGenesisBlock()이라는 명확한 이름의 함수를 호출하면 됩니다.

제네시스 블록 생성 함수의 핵심 특징은 다음과 같습니다. 첫째, 모든 노드에서 동일한 제네시스 블록을 보장합니다.

둘째, 제네시스 블록의 속성을 한 곳에서 관리하여 변경이 용이합니다. 셋째, 함수 이름이 의도를 명확히 드러내 코드 가독성이 향상됩니다.

이러한 특징들이 블록체인 초기화를 안전하고 일관되게 만듭니다.

코드 예제

import * as crypto from 'crypto';

// 제네시스 블록 생성 함수
function createGenesisBlock(): Block {
  const index = 0;
  const timestamp = 1704067200000; // 2024-01-01 00:00:00
  const data = "Genesis Block - Bitcoin Clone";
  const previousHash = "0";

  // 제네시스 블록의 해시 계산
  const hash = crypto
    .createHash('sha256')
    .update(index + timestamp + data + previousHash)
    .digest('hex');

  // Block 인스턴스 생성 및 반환
  return new Block(index, timestamp, data, previousHash, hash);
}

// 사용 예시
const genesis = createGenesisBlock();
console.log(genesis.toString()); // "Block #0 [8165349..."

설명

이것이 하는 일: createGenesisBlock 함수는 제네시스 블록의 모든 속성을 미리 정의된 값으로 설정하고, 해시를 계산한 뒤 Block 인스턴스를 생성하여 반환합니다. 첫 번째로, 제네시스 블록의 고정된 속성값들을 정의합니다.

index는 항상 0, previousHash는 항상 "0"으로 설정됩니다. timestamp는 블록체인의 공식 시작 시간으로, 모든 노드에서 동일해야 하므로 고정된 유닉스 타임스탬프를 사용합니다.

data에는 블록체인의 목적을 나타내는 메시지를 담습니다. 이 값들을 함수 내부에 캡슐화하면 제네시스 블록 생성 로직이 한 곳에 집중됩니다.

그 다음으로, 이러한 속성값들을 기반으로 제네시스 블록의 해시를 계산합니다. calculateHash 함수를 별도로 만들었다면 재사용할 수 있지만, 여기서는 인라인으로 해시를 계산하여 의존성을 줄였습니다.

SHA-256 해시는 입력값이 동일하면 항상 동일한 결과를 생성하므로, 모든 노드가 동일한 제네시스 블록 해시를 갖게 됩니다. 함수는 계산된 모든 값을 사용하여 새로운 Block 인스턴스를 생성하고 반환합니다.

이때 Block 클래스의 생성자가 모든 속성을 검증하고 readonly로 설정하므로, 생성된 제네시스 블록은 변경될 수 없습니다. 반환 타입을 Block으로 명시하면 타입스크립트가 반환값의 타입 안정성을 보장합니다.

마지막으로, 이 함수는 매개변수를 받지 않으므로 호출할 때마다 정확히 동일한 제네시스 블록을 생성합니다. 이는 블록체인의 결정론적 특성을 보장하는 중요한 설계입니다.

만약 네트워크 ID나 체인 ID에 따라 다른 제네시스 블록을 만들어야 한다면, 매개변수로 받아 data나 timestamp에 반영할 수 있습니다. 여러분이 이 함수를 사용하면 블록체인 초기화 코드가 매우 간결해집니다.

const blockchain = new Blockchain(createGenesisBlock())처럼 한 줄로 블록체인을 시작할 수 있으며, 제네시스 블록의 일관성이 보장되어 네트워크 분기 위험이 사라집니다.

실전 팁

💡 제네시스 블록의 메시지에 버전 정보를 포함하세요. 예: "Genesis Block v1.0.0". 나중에 프로토콜이 업그레이드되어도 제네시스 블록으로 체인의 버전을 식별할 수 있습니다.

💡 테스트용과 프로덕션용 제네시스 블록을 분리하려면 환경변수를 활용하세요. const data = process.env.NODE_ENV === 'production' ? "Production Genesis" : "Test Genesis".

💡 제네시스 블록의 해시를 상수로 미리 계산하여 저장하면 매번 계산할 필요가 없어 성능이 향상됩니다. 단, 이 경우 속성값을 변경하면 상수도 함께 업데이트해야 합니다.

💡 블록체인에 특별한 설정이 필요하다면 제네시스 블록의 data를 JSON 형태로 만들어 설정값을 저장하세요. 예: data: JSON.stringify({ version: "1.0", difficulty: 4 }).

💡 제네시스 블록 생성을 별도의 모듈로 분리하면 테스트와 모킹이 쉬워집니다. genesis.ts 파일에 createGenesisBlock()을 정의하고 필요한 곳에서 import하세요.


5. 타임스탬프_관리

시작하며

여러분이 블록을 생성할 때 "타임스탬프를 어떤 형식으로 저장해야 하지? Date 객체를 쓸까, 숫자를 쓸까?"라는 고민을 해본 적 있나요?

이런 문제는 블록체인의 정렬, 검색, 직렬화에 큰 영향을 미칩니다. 잘못된 타임스탬프 형식을 사용하면 타임존 문제로 블록 순서가 뒤바뀌거나, JSON 직렬화 시 데이터가 손실될 수 있습니다.

특히 분산 시스템에서는 여러 노드의 시간이 정확히 일치하지 않을 수 있어 더욱 신중한 설계가 필요합니다. 바로 이럴 때 필요한 것이 유닉스 타임스탬프를 활용한 표준화된 시간 관리입니다.

밀리초 단위의 숫자로 시간을 저장하면 타임존에 독립적이고 비교가 쉬우며 직렬화에도 안전합니다.

개요

간단히 말해서, 타임스탬프 관리는 블록 생성 시간을 유닉스 타임스탬프(1970년 1월 1일 이후 밀리초)로 저장하고 관리하는 시스템입니다. 유닉스 타임스탬프는 1970년 1월 1일 00:00:00 UTC를 기준점(epoch)으로 하여 경과한 밀리초를 숫자로 표현합니다.

예를 들어, 1704067200000은 2024년 1월 1일 00:00:00 UTC를 의미합니다. 이 방식은 운영체제, 프로그래밍 언어, 데이터베이스에 관계없이 동일하게 해석되므로 블록체인처럼 분산된 시스템에서 이상적입니다.

기존에는 "2024-01-01T00:00:00Z" 같은 ISO 8601 문자열을 사용했다면, 블록체인에서는 숫자 타임스탬프를 사용하여 비교 연산을 단순화하고 저장 공간을 절약합니다. 타임스탬프 관리의 핵심 특징은 다음과 같습니다.

첫째, 타임존에 독립적이어서 전 세계 어디서나 동일하게 해석됩니다. 둘째, 숫자이므로 크기 비교가 간단합니다(a.timestamp > b.timestamp).

셋째, JSON 직렬화 시 데이터 손실이 없습니다. 이러한 특징들이 분산 블록체인 시스템의 시간 일관성을 보장합니다.

코드 예제

// 현재 시간의 타임스탬프 생성
function getCurrentTimestamp(): number {
  return Date.now(); // 밀리초 단위 유닉스 타임스탬프
}

// 타임스탬프를 읽기 쉬운 형식으로 변환
function formatTimestamp(timestamp: number): string {
  return new Date(timestamp).toISOString();
}

// 블록 생성 시 타임스탬프 사용
function createBlock(index: number, data: string, previousHash: string): Block {
  const timestamp = getCurrentTimestamp();
  const hash = calculateHash(index, timestamp, data, previousHash);
  return new Block(index, timestamp, data, previousHash, hash);
}

// 사용 예시
const block = createBlock(1, "Transaction data", "abc123...");
console.log(`Block created at: ${formatTimestamp(block.timestamp)}`);
// "Block created at: 2024-01-15T10:30:45.123Z"

설명

이것이 하는 일: 타임스탬프 관리 시스템은 블록 생성 시점을 정확하고 일관되게 기록하며, 블록체인 내에서 시간 기반 작업을 가능하게 합니다. 첫 번째로, Date.now()를 사용하여 현재 시간을 밀리초 단위의 숫자로 가져옵니다.

이 함수는 시스템의 현재 UTC 시간을 1970년 1월 1일 이후 경과한 밀리초로 반환합니다. 숫자로 저장하면 타입스크립트의 number 타입을 그대로 사용할 수 있어 타입 안정성이 유지되며, Date 객체처럼 직렬화 시 특별한 처리가 필요 없습니다.

그 다음으로, 저장된 타임스탬프를 사람이 읽을 수 있는 형식으로 변환하는 헬퍼 함수를 제공합니다. formatTimestamp()는 숫자 타임스탬프를 받아 ISO 8601 형식의 문자열로 변환합니다.

예를 들어, 1705318245123을 "2024-01-15T10:30:45.123Z"로 변환합니다. 이는 로그 출력이나 UI 표시에 유용하며, Z 접미사는 UTC 시간임을 명시합니다.

블록 생성 시에는 getCurrentTimestamp()를 호출하여 현재 시간을 가져온 뒤, 이를 블록의 timestamp 속성에 저장합니다. 이 타임스탬프는 블록 해시 계산에도 포함되므로, 동일한 데이터로 만든 블록이라도 생성 시간이 다르면 다른 해시를 갖게 됩니다.

이는 블록의 고유성을 보장하는 중요한 메커니즘입니다. 마지막으로, 숫자 타임스탬프를 사용하면 블록의 시간 순서를 쉽게 정렬할 수 있습니다.

blocks.sort((a, b) => a.timestamp - b.timestamp)처럼 간단한 수식으로 오름차순 정렬이 가능합니다. 또한 특정 시간 범위의 블록을 필터링할 때도 blocks.filter(b => b.timestamp > startTime && b.timestamp < endTime)처럼 직관적인 코드를 작성할 수 있습니다.

여러분이 이 타임스탬프 시스템을 사용하면 블록체인의 시간적 일관성이 보장됩니다. 서로 다른 서버나 국가에서 실행되는 노드들도 동일한 방식으로 시간을 해석하므로, 블록 검증과 동기화가 정확하게 이루어집니다.

실전 팁

💡 서버 시간이 부정확하면 블록 타임스탬프도 부정확해집니다. NTP(Network Time Protocol)를 사용하여 서버 시간을 주기적으로 동기화하세요.

💡 타임스탬프 검증을 추가하여 미래 시간의 블록이나 너무 오래된 블록을 거부하세요. 예: if (timestamp > Date.now() + 60000) throw new Error("Future block").

💡 블록 생성 간격을 측정하려면 이전 블록과의 타임스탬프 차이를 계산하세요. const timeDiff = currentBlock.timestamp - previousBlock.timestamp. 이는 네트워크 성능 모니터링에 유용합니다.

💡 데이터베이스에 저장할 때는 BIGINT 타입을 사용하세요. JavaScript의 number는 64비트 부동소수점이지만, 밀리초 타임스탬프는 53비트 정수 범위 내에 있어 안전합니다.

💡 마이크로초 단위의 더 높은 정밀도가 필요하다면 process.hrtime.bigint()를 사용하세요. 단, 이 경우 BigInt 타입을 사용해야 하며 JSON 직렬화 시 커스텀 처리가 필요합니다.


6. 블록_데이터_구조

시작하며

여러분이 블록에 데이터를 저장할 때 "단순 문자열로 충분할까? 아니면 복잡한 객체 구조가 필요할까?"라는 고민을 해본 적 있나요?

이런 문제는 블록체인의 확장성과 직결됩니다. 초기에는 간단한 문자열로 시작하지만, 나중에 트랜잭션, 스마트 컨트랙트, 메타데이터 등 복잡한 데이터를 저장해야 할 때 구조가 없으면 리팩토링이 매우 어려워집니다.

또한 데이터 검증, 직렬화, 쿼리도 복잡해집니다. 바로 이럴 때 필요한 것이 제네릭을 활용한 유연한 블록 데이터 구조입니다.

처음에는 문자열로 시작하되, 나중에 복잡한 타입으로 확장할 수 있는 설계가 중요합니다.

개요

간단히 말해서, 블록 데이터 구조는 블록에 저장될 정보의 형태를 정의하며, 타입스크립트의 제네릭을 활용하면 다양한 데이터 타입을 안전하게 지원할 수 있습니다. 실무에서 블록체인은 다양한 종류의 데이터를 저장합니다.

암호화폐라면 트랜잭션 배열, 공급망이라면 상품 정보, 의료 기록이라면 환자 데이터 등입니다. 처음부터 특정 구조에 종속되면 다른 용도로 확장하기 어려워집니다.

제네릭을 사용하면 Block<T> 형태로 정의하여 어떤 타입의 데이터도 저장할 수 있습니다. 기존에는 data: any를 사용하여 타입 안정성을 포기했다면, 제네릭을 사용하면 타입 안정성을 유지하면서도 유연성을 확보할 수 있습니다.

블록 데이터 구조의 핵심 특징은 다음과 같습니다. 첫째, 제네릭으로 다양한 데이터 타입을 지원합니다.

둘째, 직렬화 가능한 구조를 사용하여 네트워크 전송과 저장이 용이합니다. 셋째, 타입 안정성을 통해 컴파일 타임에 오류를 감지합니다.

이러한 특징들이 확장 가능하고 안전한 블록체인 데이터 관리를 가능하게 합니다.

코드 예제

// 제네릭을 활용한 Block 클래스
class Block<T> {
  public readonly index: number;
  public readonly timestamp: number;
  public readonly data: T; // 제네릭 타입
  public readonly previousHash: string;
  public readonly hash: string;

  constructor(
    index: number,
    timestamp: number,
    data: T,
    previousHash: string,
    hash: string
  ) {
    this.index = index;
    this.timestamp = timestamp;
    this.data = data;
    this.previousHash = previousHash;
    this.hash = hash;
  }
}

// 트랜잭션 데이터 타입 정의
interface Transaction {
  from: string;
  to: string;
  amount: number;
}

// 사용 예시
const genesisBlock = new Block<string>(0, Date.now(), "Genesis Block", "0", "hash...");
const txBlock = new Block<Transaction[]>(1, Date.now(),
  [{ from: "Alice", to: "Bob", amount: 50 }],
  genesisBlock.hash, "hash...");

설명

이것이 하는 일: 제네릭 블록 데이터 구조는 블록체인이 문자열, 객체, 배열 등 다양한 형태의 데이터를 저장하면서도 타입스크립트의 타입 검사를 받을 수 있도록 합니다. 첫 번째로, Block 클래스를 Block<T> 형태로 정의하여 데이터 타입을 매개변수화합니다.

T는 타입 매개변수로, Block을 생성할 때 구체적인 타입으로 대체됩니다. 예를 들어, Block<string>은 문자열 데이터를 저장하는 블록, Block<Transaction[]>은 트랜잭션 배열을 저장하는 블록이 됩니다.

이렇게 하면 하나의 Block 클래스로 모든 데이터 타입을 처리할 수 있습니다. 그 다음으로, data 속성의 타입을 T로 선언합니다.

이는 블록을 생성할 때 지정한 타입과 정확히 일치하는 데이터만 저장할 수 있음을 의미합니다. 타입스크립트 컴파일러가 txBlock.data[0].amount처럼 접근할 때 amount가 number임을 알고 있으므로, IDE의 자동완성과 타입 검사가 완벽하게 작동합니다.

잘못된 타입의 데이터를 할당하려고 하면 컴파일 오류가 발생합니다. Transaction 인터페이스처럼 명확한 데이터 구조를 정의하면 블록에 저장되는 데이터의 형태를 문서화할 수 있습니다.

from, to, amount 같은 필드가 필수임을 타입 시스템이 보장하므로, 불완전한 트랜잭션이 블록에 저장되는 것을 방지합니다. 또한 인터페이스를 확장하여 signature, timestamp 같은 필드를 추가할 수 있습니다.

마지막으로, 해시 계산 시 데이터를 문자열로 변환해야 합니다. 제네릭 타입 T가 객체나 배열이라면 JSON.stringify(data)를 사용하여 직렬화합니다.

이때 주의할 점은 JSON.stringify()가 속성 순서를 보장하지 않으므로, 일관된 해시를 얻으려면 속성을 정렬하거나 커스텀 직렬화 함수를 사용해야 합니다. 여러분이 이 제네릭 구조를 사용하면 블록체인이 진화해도 코드 변경이 최소화됩니다.

새로운 데이터 타입을 추가할 때 Block 클래스를 수정할 필요 없이, 새로운 인터페이스를 정의하고 Block<NewType>으로 사용하면 됩니다. 이는 개방-폐쇄 원칙(Open-Closed Principle)을 따르는 설계입니다.

실전 팁

💡 제네릭 타입에 제약을 추가하려면 Block<T extends Serializable> 형태를 사용하세요. Serializable 인터페이스를 정의하여 toJSON() 메서드를 강제하면 모든 데이터가 직렬화 가능함을 보장할 수 있습니다.

💡 복잡한 객체를 해시할 때는 canonical-json 같은 라이브러리를 사용하세요. 속성 순서를 정규화하여 항상 동일한 JSON 문자열을 생성합니다.

💡 데이터 크기를 제한하려면 생성자에서 검증 로직을 추가하세요. 예: if (JSON.stringify(data).length > 1000000) throw new Error("Data too large"). 블록 크기 제한은 네트워크 성능에 중요합니다.

💡 민감한 데이터를 저장할 때는 암호화를 고려하세요. data를 저장하기 전에 AES로 암호화하고, 해시 계산에는 암호화된 데이터를 사용하면 블록체인의 투명성을 유지하면서도 프라이버시를 보호할 수 있습니다.

💡 타입 가드를 활용하여 런타임에 데이터 타입을 검증하세요. function isTransaction(data: any): data is Transaction { return 'from' in data && 'to' in data && 'amount' in data; } 같은 함수로 타입 안전성을 런타임까지 확장할 수 있습니다.


7. 이전_블록_해시_연결

시작하며

여러분이 블록체인의 체인 구조를 만들 때 "각 블록을 어떻게 연결해야 하지? 체인이 끊어지지 않도록 하려면?"이라는 고민을 해본 적 있나요?

이런 문제는 블록체인의 핵심 보안 메커니즘과 관련이 있습니다. 블록들이 제대로 연결되지 않으면 블록체인이 아니라 단순한 블록 리스트가 되어버립니다.

또한 누군가 중간 블록을 변조하면 체인 전체의 무결성이 깨지는데, 이를 감지하지 못하면 블록체인의 신뢰성이 무너집니다. 바로 이럴 때 필요한 것이 이전 블록 해시를 통한 체인 연결입니다.

각 블록이 이전 블록의 해시를 저장하면 체인 구조가 형성되고, 변조 시도를 즉시 감지할 수 있습니다.

개요

간단히 말해서, 이전 블록 해시 연결은 각 블록이 바로 앞 블록의 해시값을 previousHash 속성에 저장하여 블록들을 연결하는 메커니즘입니다. 블록체인의 "체인"이라는 이름은 바로 이 연결 메커니즘에서 유래합니다.

블록 A의 해시가 "abc123"이면, 다음 블록 B의 previousHash는 "abc123"이 됩니다. 이렇게 하면 블록들이 마치 사슬처럼 연결되며, 중간의 어떤 블록이라도 변조되면 그 블록의 해시가 바뀌고, 결과적으로 모든 후속 블록의 previousHash가 일치하지 않게 되어 변조를 감지할 수 있습니다.

기존에는 배열의 인덱스로만 블록 순서를 관리했다면, previousHash를 사용하면 암호학적으로 보증된 순서를 구현할 수 있습니다. 이전 블록 해시 연결의 핵심 특징은 다음과 같습니다.

첫째, 체인의 무결성을 암호학적으로 보장합니다. 둘째, 블록 순서가 변조 불가능하게 고정됩니다.

셋째, 체인의 어느 지점에서든 검증이 가능합니다. 이러한 특징들이 블록체인을 위변조가 불가능한 분산 원장으로 만듭니다.

코드 예제

// 새 블록 생성 함수 (이전 블록 해시 연결)
function createNextBlock(previousBlock: Block<string>, data: string): Block<string> {
  const index = previousBlock.index + 1;
  const timestamp = Date.now();
  const previousHash = previousBlock.hash; // 이전 블록의 해시 사용

  // 새 블록의 해시 계산 (previousHash 포함)
  const hash = crypto
    .createHash('sha256')
    .update(index + timestamp + data + previousHash)
    .digest('hex');

  return new Block(index, timestamp, data, previousHash, hash);
}

// 사용 예시
const genesis = createGenesisBlock();
const block1 = createNextBlock(genesis, "First transaction");
const block2 = createNextBlock(block1, "Second transaction");

console.log(`Genesis: ${genesis.hash.substring(0, 10)}...`);
console.log(`Block 1 previousHash: ${block1.previousHash.substring(0, 10)}...`);
console.log(`Block 2 previousHash: ${block2.previousHash.substring(0, 10)}...`);

설명

이것이 하는 일: 이전 블록 해시 연결은 블록들을 암호학적으로 연결하여 블록체인의 순서와 무결성을 동시에 보장하는 핵심 메커니즘입니다. 첫 번째로, createNextBlock 함수는 이전 블록(previousBlock)을 매개변수로 받습니다.

이는 새로운 블록이 반드시 기존 블록과 연결되어야 함을 강제하는 설계입니다. 함수 시그니처만으로도 블록이 단독으로 생성될 수 없음을 명확히 하며, 타입스크립트가 이전 블록 없이 블록을 생성하려는 시도를 컴파일 타임에 차단합니다.

그 다음으로, 새 블록의 previousHash를 이전 블록의 hash로 설정합니다. 이 단계가 바로 블록들을 연결하는 핵심입니다.

previousHash는 이전 블록의 모든 데이터(index, timestamp, data, previousHash)의 암호학적 요약이므로, 이전 블록이나 그 이전의 어떤 블록이라도 변조되면 이 값이 일치하지 않게 됩니다. 이는 마치 봉인된 편지처럼, 봉인이 깨지면 즉시 알 수 있는 구조입니다.

새 블록의 해시를 계산할 때 previousHash를 포함시킵니다. 이는 매우 중요한데, 새 블록의 해시가 이전 블록의 해시에 의존하게 만들어 체인 전체가 하나의 연결된 구조를 이루게 합니다.

만약 블록 1이 변조되면 블록 1의 해시가 바뀌고, 블록 2의 previousHash와 일치하지 않게 되며, 블록 2의 해시를 다시 계산하면 기존 해시와 달라져 블록 3의 previousHash와도 일치하지 않게 됩니다. 이렇게 변조 효과가 체인 끝까지 전파됩니다.

마지막으로, index도 1씩 증가시켜 블록의 순서를 명시적으로 표시합니다. previousHash만으로도 순서를 보장할 수 있지만, index를 함께 사용하면 체인의 길이를 빠르게 파악하고 특정 위치의 블록을 효율적으로 찾을 수 있습니다.

index와 previousHash의 조합은 이중 검증 메커니즘을 제공합니다. 여러분이 이 연결 메커니즘을 사용하면 블록체인의 불변성이 수학적으로 보장됩니다.

공격자가 과거의 블록을 변조하려면 그 블록의 해시를 다시 계산해야 하고, 그러면 다음 블록의 previousHash가 일치하지 않게 되어 다음 블록도 다시 계산해야 하며, 이 과정이 체인 끝까지 반복됩니다. 체인이 길어질수록 변조 비용이 기하급수적으로 증가합니다.

실전 팁

💡 블록 검증 함수를 구현하여 previousHash가 실제로 이전 블록의 해시와 일치하는지 확인하세요. function isValidNewBlock(newBlock: Block, previousBlock: Block): boolean { return newBlock.previousHash === previousBlock.hash; }

💡 체인 전체의 무결성을 검증하려면 제네시스 블록부터 마지막 블록까지 순회하며 각 블록의 연결을 확인하세요. 하나라도 불일치하면 체인이 손상된 것입니다.

💡 분산 환경에서는 여러 노드가 동시에 블록을 추가할 수 있어 체인 분기(fork)가 발생할 수 있습니다. 이때는 가장 긴 체인을 유효한 체인으로 인정하는 합의 알고리즘을 구현하세요.

💡 블록체인을 데이터베이스에 저장할 때 previousHash에 인덱스를 생성하면 특정 블록의 다음 블록을 빠르게 찾을 수 있습니다. 이는 체인 순회 성능을 크게 향상시킵니다.

💡 머클 트리(Merkle Tree)를 도입하면 블록 내부의 트랜잭션 검증도 효율적으로 할 수 있습니다. 비트코인은 이 방식으로 수천 개의 트랜잭션을 하나의 머클 루트 해시로 요약합니다.


8. 블록체인_클래스_초기화

시작하며

여러분이 블록체인 시스템을 구축할 때 "블록들을 어떻게 관리하지? 배열?

연결 리스트? 아니면 별도의 클래스?"라는 고민을 해본 적 있나요?

이런 문제는 블록체인의 구조와 기능에 큰 영향을 미칩니다. 단순히 배열로 블록을 관리하면 블록 추가, 검증, 조회 같은 작업을 할 때마다 로직이 흩어지고 중복됩니다.

또한 블록체인의 상태를 캡슐화하지 못하면 외부에서 직접 수정할 수 있어 무결성이 깨질 위험이 있습니다. 바로 이럴 때 필요한 것이 Blockchain 클래스를 통한 체계적인 체인 관리입니다.

블록들을 내부에 캡슐화하고, 블록 추가와 검증 같은 작업을 메서드로 제공하면 안전하고 일관된 블록체인 운영이 가능합니다.

개요

간단히 말해서, Blockchain 클래스는 블록들의 집합을 관리하고, 블록 추가, 검증, 조회 같은 블록체인 작업을 제공하는 컨테이너 클래스입니다. 실무에서 블록체인 애플리케이션은 단순히 블록을 저장하는 것 이상의 기능이 필요합니다.

새로운 블록이 유효한지 검증하고, 가장 최근 블록을 조회하고, 전체 체인의 무결성을 확인하는 등의 작업이 필요합니다. Blockchain 클래스를 만들면 이러한 모든 로직을 한 곳에 모아 관리할 수 있으며, 블록체인의 상태를 private으로 보호하여 외부에서 임의로 수정할 수 없게 만듭니다.

기존에는 전역 배열에 블록을 저장하고 여러 함수로 조작했다면, 클래스를 사용하면 데이터와 로직을 하나의 응집된 단위로 관리할 수 있습니다. Blockchain 클래스의 핵심 특징은 다음과 같습니다.

첫째, 제네시스 블록으로 자동 초기화됩니다. 둘째, private 배열로 블록을 저장하여 캡슐화를 보장합니다.

셋째, 블록 추가, 조회, 검증 메서드를 제공하여 일관된 인터페이스를 제공합니다. 이러한 특징들이 안전하고 사용하기 쉬운 블록체인 시스템을 만듭니다.

코드 예제

// Blockchain 클래스 정의
class Blockchain<T> {
  // private으로 블록 배열 보호
  private chain: Block<T>[];

  // 생성자: 제네시스 블록으로 초기화
  constructor(genesisBlock: Block<T>) {
    this.chain = [genesisBlock];
  }

  // 가장 최근 블록 조회
  public getLatestBlock(): Block<T> {
    return this.chain[this.chain.length - 1];
  }

  // 새 블록 추가
  public addBlock(data: T): void {
    const previousBlock = this.getLatestBlock();
    const newBlock = createNextBlock(previousBlock, data);
    this.chain.push(newBlock);
  }

  // 체인 전체 조회 (읽기 전용 복사본)
  public getChain(): readonly Block<T>[] {
    return [...this.chain];
  }
}

// 사용 예시
const genesis = createGenesisBlock();
const blockchain = new Blockchain(genesis);
blockchain.addBlock("First block data");
blockchain.addBlock("Second block data");
console.log(`Chain length: ${blockchain.getChain().length}`);

설명

이것이 하는 일: Blockchain 클래스는 블록체인의 모든 블록을 안전하게 저장하고 관리하며, 블록 추가와 조회를 위한 명확한 인터페이스를 제공합니다. 첫 번째로, 생성자에서 제네시스 블록을 매개변수로 받아 체인을 초기화합니다.

이는 블록체인이 항상 유효한 제네시스 블록으로 시작함을 보장합니다. this.chain = [genesisBlock]로 배열의 첫 번째 요소로 제네시스 블록을 설정하면, 체인의 길이가 최소 1이 되어 빈 체인이 생성될 수 없습니다.

타입스크립트의 타입 시스템이 생성자 호출 시 제네시스 블록을 강제하므로 초기화 오류를 방지합니다. 그 다음으로, chain 배열을 private으로 선언하여 외부에서 직접 접근할 수 없도록 합니다.

이는 캡슐화의 핵심 원칙으로, 블록체인의 무결성을 보호합니다. 외부 코드가 blockchain.chain[0] = someBlock처럼 직접 수정하려고 하면 타입스크립트 컴파일러가 오류를 발생시킵니다.

블록 추가는 반드시 addBlock() 메서드를 통해서만 가능하므로, 검증 로직을 거치지 않은 블록이 추가될 수 없습니다. getLatestBlock() 메서드는 체인의 마지막 블록을 반환합니다.

이는 새로운 블록을 추가할 때 자주 사용되는 패턴으로, 배열의 길이에서 1을 빼서 마지막 인덱스를 계산합니다. 이 메서드를 제공하면 외부 코드가 체인 구조를 알 필요 없이 최신 블록을 가져올 수 있습니다.

또한 나중에 체인을 배열에서 다른 자료구조로 변경해도 이 메서드의 인터페이스는 유지되므로 리팩토링이 쉽습니다. addBlock() 메서드는 블록 추가 로직을 캡슐화합니다.

내부적으로 getLatestBlock()을 호출하여 이전 블록을 가져오고, createNextBlock()으로 새 블록을 생성한 뒤, 체인에 추가합니다. 이 과정이 모두 메서드 내부에 숨겨져 있어 외부에서는 단순히 데이터만 전달하면 됩니다.

나중에 블록 검증 로직을 추가하려면 이 메서드만 수정하면 되므로 변경의 영향 범위가 제한됩니다. 마지막으로, getChain() 메서드는 체인의 복사본을 반환합니다.

[...this.chain]은 스프레드 연산자로 배열을 복사하는데, 이렇게 하면 외부에서 반환된 배열을 수정해도 원본 체인은 영향받지 않습니다. readonly 타입을 반환하면 타입스크립트가 반환된 배열의 수정 시도를 컴파일 타임에 차단합니다.

이는 불변성을 보장하는 방어적 복사(defensive copying) 패턴입니다. 여러분이 이 Blockchain 클래스를 사용하면 블록체인을 객체 지향적으로 관리할 수 있습니다.

모든 블록체인 작업이 명확한 메서드로 정의되어 코드의 가독성과 유지보수성이 향상되며, 캡슐화를 통해 블록체인의 무결성이 보호됩니다. 테스트 작성도 쉬워지고, 나중에 데이터베이스 연동이나 네트워크 동기화 같은 고급 기능을 추가하기도 용이합니다.

실전 팁

💡 블록 검증 로직을 addBlock()에 추가하여 잘못된 블록이 체인에 추가되는 것을 방지하세요. 예: if (!isValidNewBlock(newBlock, previousBlock)) throw new Error("Invalid block").

💡 체인의 전체 무결성을 검증하는 isValidChain() 메서드를 구현하세요. 제네시스 블록부터 시작하여 모든 블록의 연결과 해시를 검증하면 체인이 손상되지 않았는지 확인할 수 있습니다.

💡 블록을 인덱스로 조회하는 getBlockByIndex(index: number) 메서드를 추가하면 특정 블록을 빠르게 찾을 수 있습니다. 범위 검증을 추가하여 유효하지 않은 인덱스에 대해 에러를 던지세요.

💡 큰 블록체인을 다룰 때는 전체 체인을 메모리에 유지하지 말고 데이터베이스에 저장하세요. 최근 블록 일부만 메모리에 캐시하고 나머지는 필요할 때 로드하는 방식으로 메모리 사용을 최적화할 수 있습니다.

💡 이벤트 시스템을 추가하여 블록이 추가될 때마다 리스너에게 알리세요. private listeners: Array<(block: Block<T>) => void> = []public onBlockAdded(listener: ...) 패턴으로 구현하면 블록 추가 시 로깅, 알림, 동기화 등을 쉽게 처리할 수 있습니다.


#TypeScript#Blockchain#GenesisBlock#CryptoHash#BlockStructure#typescript

댓글 (0)

댓글을 작성하려면 로그인이 필요합니다.