3. 핵심 아키텍처

3.1 3계층 캐시 + TX풀 통합 아키텍처

캐시매니저는 3계층 캐시와 TX풀을 단일 잠금로 통합 제어하는 중앙 관제소. UTXO 조회, 잔액 계산, 이중지불 검사를 모두 흡수하여 원자적 상태 검사를 보장.

UBMS::CacheManager (내부 조회가 O(10) 이하라 잠금 점유 시간이 극히 짧다)
  │
  ├──  UBMS::TxCurrent (TX풀 + 주소별 예약 풀)
  │       m_tx: 타임스탬프 순 TX 맵
  │       m_reserved: 주소별 UBMS::UtxoPool
  │         ├─ spent_keys: 소비 예약된 UTXO key
  │         ├─ spent_list: 소비 입력 목록
  │         └─ available: TX풀 잔돈 (미소비 UTXO)
  │       m_globalSpentKeys: 크로스-주소 이중소비 방어
  │
  ├──  [1층] UBMS::VolatileCache (최근 10블록)
  │       std::list<UBMS::BlockDelta> m_deltas
  │       UBMS::BlockDelta = {
  │         m_addedUtxo:      새로 생긴 UTXO (맵)
  │         m_spentKeys:      소비된 UTXO key (셋)
  │         m_spentUtxoInfo:  소비 UTXO의 owner/miner
  │         m_transactions:   TX 목록 (서명 제거)
  │         m_addedReferrals: 새 추천인 관계
  │         m_mineAddress, m_reward
  │       }
  │       롤백 = popBack 한 번이면 끝
  │       조회 = 최신부터 역순 탐색 (O(10) 최대)
  │
  ├──  [2층] UBMS::ConfirmedCache (메모리 상주)
  │       m_childToParent:     리퍼럴 1:1 맵
  │       m_parentToChildren:  리퍼럴 1:N 맵
  │       m_nodeInfo:          채굴자별 통계
  │       m_mineTimeLast:      최근 100블록 채굴 시간
  │
  └──  [3층] DB (영구 저장소)
          TX, UTXO, 소유자/채굴자/주소 인덱스 저장
          Bloom filter로 미존재 키 빠른 제외

조회 우선순위 (상위 캐시부터 폴백)

UTXO 소비 확인 (isSpentKey):
  1) volatile.spentKeys → true면 즉시 소비됨
  2) volatile.addedUtxo → 있으면 미소비
  3) DB 조회 → 없으면 소비됨

잔액 조회 (getBalance):
  DB(owner 인덱스) + volatile(addedUtxo - spentKeys) 합산

TX풀 통합 조회 (getInputWithPool):
  DB UTXO + volatile 필터링 + TX풀 잔돈(available) 결합

블록차분 변경분 추출 (makeDelta)

블록 하나가 차분 하나로 변환되는 과정:

makeDelta(block):
  단계 1: 블록 기본 정보 복사 (height, hash, mineAddress, reward)

  단계 2: 각 TX 처리
    a) signature, publicKey 제거 → m_transactions (메모리 절약)
    b) output → UBMS::S_UTXO 변환 → m_addedUtxo[txid:index]
    c) input → m_spentKeys.insert(txid:index)
    d) referral → m_addedReferrals.push_back({child, parent})

  단계 3: 스테이킹 리워드 → m_addedUtxo에 추가

  단계 4: 중복 제거 (같은 TX에서 추가+삭제면 삭제 우선)
    for each spentKey: m_addedUtxo.erase(key)

  단계 5: spent UTXO 정보 사전 수집 
    for each spentKey:
      volatile 또는 DB에서 owner/minerAddress를 미리 조회
      → m_spentUtxoInfo[key] = {owner, minerAddress}
      → DB 커밋 시 getUTXO 실패해도 인덱스 안전하게 삭제 가능

영리한 롤백 전략

추가 (addBlock):
  makeDelta(block)
  → m_confirmed.applyDelta(delta)   // 리퍼럴/노드정보 즉시 반영
  → m_volatile.pushBack(delta)      // delta 리스트에 추가
  → if size > 10: popFront → commitToDb()  // 오래된 것 DB 이관

롤백 (rollBack):
  m_volatile.popBack()               // delta 통째로 제거 (O(1))
  m_confirmed.rollbackReferrals()    // 리퍼럴 역순 제거
  m_confirmed.rollbackNodeInfo()     // 채굴 통계 감산
  → 인덱스 정리 불필요, UTXO 가감연산 불필요
  → delta 제거만으로 자동 원복

비트코인 코어의 DisconnectBlock 대비:
  비트코인: 각 TX의 input/output을 역으로 재계산 → O(TX수)
  UBMS:     delta 통째로 pop → O(1)

DB 커밋 + 인덱스 생성 (commitToDb)

volatile이 10블록을 초과하면 가장 오래된 차분을 일괄 커밋.

commitToDb(delta):
  WriteBatch _batch;   // 원자적 배치 쓰기

  1) TX 저장 + 주소별 인덱스
     for each tx:
       addTx(tx)
       addTxAddrIndex(tx.address, txid)  // 발신자 인덱스
       for each output:
         addTxAddrIndex(output.to, txid) // 수신자 인덱스

  2) UTXO 추가 + 소유자/채굴자 인덱스
     for each addedUtxo:
       addUTXO(utxo)
       addOwnerIndex(owner, key)
       if stake.LOCK:
         addMinerIndex(minerAddr, key)

  3) UTXO 삭제(spent) + 인덱스 제거 
     for each spentKey:
       if m_spentUtxoInfo에 사전 수집 정보 있으면:  ← 핵심
         owner/miner 인덱스 안전 삭제 (DB 재조회 불필요)
       else:
         DB에서 getUTXO로 조회 (폴백)
       removeUTXO(txid, index)

  4) Referral 저장
  5) CommittedHeight 갱신
  6) execBatch(_batch)  // 전부 성공하거나 전부 실패

소비 UTXO 사전수집이 핵심인 이유:

  • 차분이 10블록 뒤에 DB로 이관될 때, 원본 UTXO는 이미 volatile에서 삭제

  • DB에서 getUTXO 조회가 실패할 수 있다 (다른 차분이 먼저 커밋)

  • 사전 수집된 owner/minerAddress로 인덱스를 안전하게 삭제 → 인덱스 고아 방지

인덱스 3종 상세

인덱스

생성 시점

삭제 시점

용도

owner

UTXO 생성 시

UTXO 소비 시

주소별 잔액/UTXO 조회

miner

stake LOCK 시

UTXO 소비 시

채굴자별 위임 스테이크

txaddr

TX 커밋 시

삭제 안 함 (이력)

주소별 TX 이력 조회

getBalance(address):
  DB 소유자 인덱스 prefix 스캔
  + volatile addedUtxo 중 owner 일치
  - volatile spentKeys 제외
  = 최종 잔액

getStakeToMine(minerAddress):
  DB 채굴자 인덱스 prefix 스캔
  + volatile 중 stake.LOCK && minerAddress 일치
  = 해당 채굴자에게 위임된 스테이크 목록

getTx(address):
  DB 주소 인덱스 prefix 스캔
  + volatile m_transactions 중 address 일치
  = 해당 주소의 전체 TX 이력

동작 흐름:

블록 추가 -> makeDelta(변경분 추출) -> volatile에 pushBack
  -> 10개 넘으면 -> 가장 오래된 delta를 DB에 커밋 (배치 쓰기)
  -> TX풀 정리 -> 인덱스 생성

3.2 독자 설계 UTXO 모델

UBMS의 UTXO는 "UTXO"라는 이름만 비트코인과 같을 뿐, 내부 구조는 완전히 독자 설계. 비트코인의 Script 기반 잠금/해제 모델을 사용하지 않으며, 독자적인 타입 시스템 위에 구축.

비트코인 UTXO vs UBMS UTXO 구조 비교

비트코인 UTXO (CTxOut)
  nValue            금액 (satoshi)
  scriptPubKey      잠금 스크립트 (Script 바이트코드)
  → Script 인터프리터가 해석하여 잠금/해제 판정
  → 고정 바이너리 직렬화 (CSerialize)
  → 스테이킹 개념 없음
  → 메타데이터 없음

UBMS UTXO (UBMS::S_UTXO : UBMS::Serializable)
  index             출력 인덱스
  amount            금액 (mensch 단위)
  timestamp         생성 시각
  owner             소유자 주소
  txid              원본 트랜잭션 ID
  stake {           스테이킹 상태 머신 (UBMS::S_STAKE)
    state           NONE → LOCK → UNLOCK 상태 전이
    minerAddress    위임 채굴자 주소
  }
  ubms {            메타데이터 컨트랙트 (UBMS::S_UBMS)
    metaData        JSON 형태 온체인 메타데이터
    ttl             유효기간 (만료 시 자동 소멸)
    conditions      조건부 실행 규칙
  }

독자 타입 시스템 (UBMS::Serializable)

UBMS의 모든 데이터 구조는 독자 개발된 Serializable 프레임워크를 상속. 비트코인의 CSerialize 매크로나 이더리움의 RLP 인코딩과는 완전히 다른 설계.

UBMS::Serializable (기반 클래스)
  ├─ describe() 순수 가상 함수로 필드를 자기서술적으로 등록
  ├─ reg()         기본 타입 (uint64_t, string, bool, float, double)
  ├─ regEnum()     범위 검증 포함 열거형
  ├─ regStruct()   중첩 구조체 (재귀 직렬화)
  ├─ regVec()      구조체 벡터 (OOM 방어: 크기 상한 제한)
  ├─ regSet()      문자열 집합
  ├─ regRawTail()  나머지 버퍼 전체를 raw 바이너리로
  ├─ regPtrStatus() shared_ptr 존재 여부만 bool로
  │
  ├─ toJson() / fromJson()           JSON 자동 변환
  ├─ serialize() / deserialize()     바이너리 자동 변환
  └─ E_REG_FLAG: REG_ALL / REG_JSON_ONLY / REG_BIN_ONLY  포맷별 필드 선택

핵심 설계 원리:

1. 자기서술적:  describe()에서 필드를 등록하면 JSON/바이너리 양방향 직렬화가 자동 생성됨
2. 이중 포맷:   하나의 구조체가 REST API용 JSON과 P2P용 바이너리를 동시에 지원
3. 재귀 합성:     regStruct/regVec으로 복합 구조체를 제한 없이 중첩 가능
4. 안전한 역직렬화: 버퍼 경계 검사, 벡터 크기 상한, enum 범위 검증, 타입 불일치 무시
5. 포맷 분리:     REG_JSON_ONLY/REG_BIN_ONLY로 네트워크 전송용과 API 응답용 필드를 분리

UBMS 타입 계층도

UBMS::Serializable (libubmstype.so)
  │
  ├── UBMS::S_UBMS            메타데이터 (metaData, ttl, conditions)
  ├── UBMS::S_STAKE           스테이킹 상태 (state, minerAddress)
  ├── UBMS::S_INPUT           TX 입력 (txid, index, amount, stake, ubms)
  ├── UBMS::S_OUTPUT          TX 출력 (to, amount, index, stake, ubms)
  ├── UBMS::S_REFERRAL        리퍼럴 관계 (child, parent, ref[])
  ├── UBMS::S_REFERRAL_TREE   리퍼럴 트리 (재귀 구조: name, level, children[])
  ├── UBMS::S_REWARD          보상 정보 (owner, amount, reward, txid)
  ├── UBMS::S_TRANSACTION     트랜잭션 (type, in[], out[], referral, signature)
  ├── UBMS::S_BLOCK           블록 (헤더 + transaction[] + stakeReward[])
  ├── UBMS::S_BLOCK_META      블록 저장 위치 (fileName, fileOffset, dataSize)
  ├── UBMS::S_BLOCK_MINI      경량 블록 (검증에 필요한 최소 필드만 포함)
  ├── UBMS::S_HEIGHT          피어 높이 정보
  ├── UBMS::S_MINE_INFO       채굴 정보 (stakers[], transactions[], height)
  ├── UBMS::S_WALLET          지갑 (address, balance, publicKey)
  ├── UBMS::S_MESSAGE         P2P 메시지 (header, path[], avoid{}, payload)
  │                           setPayload<T>() / getPayload<T>() 범용 페이로드
  │
  ├── UBMS::S_INPUT_LIST      입력 목록 컨테이너 (독립 직렬화)
  ├── UBMS::S_BLOCK_LIST      블록 목록 컨테이너 (독립 직렬화)
  └── UBMS::S_TRANSACTION_LIST 트랜잭션 목록 컨테이너 (독립 직렬화)

비트코인과의 핵심 차이 요약

항목

Bitcoin UTXO

UBMS UTXO

잠금 모델

Script 바이트코드 (OP_DUP, OP_HASH160...)

상태 머신 (NONE→LOCK→UNLOCK)

스크립트 VM

Script 인터프리터 필수

VM 없음 — 네이티브 C++ 처리

스테이킹

불가능 (외부 프로토콜 필요)

UTXO 자체에 S_STAKE 내장

메타데이터

OP_RETURN 80바이트 제한

S_UBMS: JSON 메타 + TTL + 조건 무제한

직렬화

CSerialize 매크로 (바이너리 전용)

Serializable: JSON + 바이너리 자동 이중 생성

추천인

불가능

S_REFERRAL: 5단계 유통인 체인 내장

보상

coinbase TX 하나

S_REWARD[]: 채굴 5% + 스테이킹 95% 분배

검증 전파

전체 블록 전송

S_BLOCK_MINI: 경량 블록으로 검증자 대역 절감

위임 채굴

불가능

S_STAKE.minerAddress로 UTXO 레벨 위임

UBMS는 UTXO라는 개념적 모델(미사용 출력 추적)만 차용했을 뿐, 잠금/해제 방식, 상태 관리, 메타데이터, 직렬화 엔진까지 전부 독자 설계.

UTXO 조회 순서:

DB(owner 인덱스) -> volatile에서 spent 필터링 -> TX풀 예약 풀 반영
= 최종 사용 가능 잔액

3.3 Shifted Sigmoid 보상 알고리즘

UBMS의 핵심 알고리즘인 Shifted Sigmoid은 스테이킹 보상을 비선형으로 분배. 대량 스테이킹 독식을 구조적으로 방지하는 것이 목적.

Sigmoid 가중치 계산 (백서 인용)

R(x)=11+e−zR(x)=1+ez1​

z=(x+sT−0.5)×10z=(Tx+s​−0.5)×10

  x : 해당 스테이커의 스테이킹 수량
  T : 전체 스테이커 스테이킹 합계
  r = 0.2 (좌측 이동 비율)
  s = T × r (이동값)
  10을 곱해 소지분과 대지분 간 격차를 유의미하게 증폭

개별 스테이커 보상 공식

reward(x)=(block reward×95%)×R(x)∑R(xi)reward(x)=(block reward×95%)×∑R(xi​)R(x)​

z=(x+T×0.2T−0.5)×10z=(Tx+T×0.2​−0.5)×10

보상 분배 구조:

블록 보상 분배:
  채굴자: 블록 보상의 5%   ← PoW
  스테이커: 블록 보상의 95% ← PoS (Shifted Sigmoid 비율로 분배)

효과:

  • 대지분 독식 방지 — 보상이 선형이 아닌 곡선화되어 고지분자가 급격히 독식 불가

  • 소지분 참여자 보정 — 적은 지분도 의미 있는 보상 획득 → 지속적 참여 유도

  • 수학적 정당성 — 시프트된 Sigmoid는 정규화 후에도 전체 보상 총합 유지

3.3.1 소각 메커니즘 (Burn Mechanism)

PoS 보상 분배 시 참여 노드 수가 적을 때 일부 보상을 자동 소각(Burn)하는 공급 조절 메커니즘이 내장되어 있다.

PoS 분배율=max⁡(0.01,min⁡(1,N10,000))×100%PoS 분배율=max(0.01,min(1,10,000N​))×100%

PoS 소각률=(1−max⁡(0.01,min⁡(1,N10,000)))×100%PoS 소각률=(1−max(0.01,min(1,10,000N​)))×100%

노드 수         분배율       소각률       비고
0              0%          100%        PoS 보상 전액 소각
100            1%           99%        1% 분배, 99% 소각
1,000         10%           90%        10% 분배, 90% 소각
5,000         50%           50%        50% 분배, 50% 소각
9,500         95%            5%        95% 분배, 5% 소각
10,000 이상    100%            0%        전액 분배, 소각 없음

설계 효과:

  • 노드 수가 적을 때 공급 자동 제한 → 인플레이션 방지

  • 노드 참여 증가 유도 → 참여자 수에 비례해 분배량 증가

  • 장기적 생태계 균형 확보 → 네트워크 건전성 유지

3.4 반감기 스케줄

초반 채굴 단계

채굴 기간: 6시간 = 6 × 60 × 60 = 21,600초
블록 생성 시간: 10초/블록
총 블록 수: 21,600 / 10 = 2,160블록
반감기 간격: 540블록
초기 보상 R₀: 1,000 UBMS/블록
반감기 횟수: 4회

구간별 채굴량:

구간 1: R₀     = 1,000 × 540 = 540,000 UBMS    (블록 0 ~ 539)
구간 2: R₀/2   =   500 × 540 = 270,000 UBMS    (블록 540 ~ 1,079)
구간 3: R₀/4   =   250 × 540 = 135,000 UBMS    (블록 1,080 ~ 1,619)
구간 4: R₀/8   =   125 × 540 =  67,500 UBMS    (블록 1,620 ~ 2,159)
─────────────────────────────────────────────

C1=∑C1i=1,012,500UBMSC1​=∑C1i​=1,012,500UBMS

후반 채굴 단계

블록 생성 시간: 10분/블록
연간 블록 수: 365 × 24 × 60 / 10 = 52,560블록/년
반감기 간격: 4 × 52,560 = 210,240블록 (약 4년)
후반 초기 보상 R₀': 48 UBMS/블록

구간별 채굴량:

 구간  5: 48    × 210,240 = 10,091,520 UBMS   (블록 2,160 ~ 212,399)
 구간  6: 24    × 210,240 =  5,045,760 UBMS   (블록 212,400 ~ 422,639)
 구간  7: 12    × 210,240 =  2,522,880 UBMS   (블록 422,640 ~ 632,879)
 구간  8:  6    × 210,240 =  1,261,440 UBMS   (블록 632,880 ~ 843,119)
 구간  9:  3    × 210,240 =    630,720 UBMS   (블록 843,120 ~ 1,053,359)
구간 10:  1.5  × 210,240 =    315,360 UBMS   (블록 1,053,360 ~ 1,263,599)
구간 11:  0.75 × 210,240 =    157,680 UBMS   (블록 1,263,600 ~ 1,473,839)
─────────────────────────────────────────────

C2=∑C2j≈20,000,000UBMSC2​=∑C2j​≈20,000,000UBMS

총 발행량 요약

총 발행=C1+C2=1,012,500+20,000,000≈21,012,500UBMS총 발행=C1​+C2​=1,012,500+20,000,000≈21,012,500UBMS

PoS 소각분을 제외하면 실제 유통량은 더 적음

3.5 PoB (Proof of Behavior) — 5단계 유통인 수수료 분배

UBMS의 세 번째 합의 축인 PoB는 "행위 증명" 메커니즘. 트랜잭션 수수료가 5단계 유통인(Distributor) 체인을 따라 온체인 자동 분배.

수수료 분배 비율 (백서 인용)

전체 수수료 = F 일 때:

  1대 (직접 추천인)    →  F × 60%
  2대                  →  F × 20%
  3대                  →  F × 10%
  4대                  →  F ×  7%
  5대 (최상위)          →  F ×  3%
  ───────────────────────────
  합계                     100%

효과:

  • 네트워크 성장에 기여한 유통인에게 지속적 인센티브 제공

  • 트랜잭션 수수료를 통한 온체인 채굴 (수수료 마이닝)

  • referral 관계는 ConfirmedCache에 메모리 상주하므로 조회가 빠름

3.6 동적 수수료 체계

수수료는 고정이 아닌 시장 상황에 따라 자동 조정. 외부 시장가 데이터를 활용하여 합리적 수수료를 산출.

수수료 공식 (백서 인용)

EF=vv0=v10,000EF=v0​v​​=10,000v​​

F=B×EF×CF=1,000×v10,000×CFF=B×EF×CF=1,000×10,000v​​×CF

  v₀ = 10,000 원 (기준 시장가)
  B  = 1,000 원 (기저 수수료)
  CF = 최근 250개 블록의 혼잡도 반영, 기본값 1.0

계산 예시:

예시 1: 시장가 v = 10,000 원
  EF = √(10,000 / 10,000) = √1 = 1
  F  = 1,000 × 1 × 1.0 = 1,000 원

예시 2: 시장가 v = 100,000,000 원
  EF = √(100,000,000 / 10,000) = √10,000 = 100
  F  = 1,000 × 100 × 1.0 = 100,000 원

비트코인과 이더리움의 수수료가 거래 금액과 무관하게 고정/혼잡 기반인 반면, UBMS는 외부 시장가 기반 경제 팩터를 도입하여 거래 규모에 비례하는 합리적 수수료를 구현.

3.7 UTXO 기반 메타데이터 스마트 컨트랙트

UBMS는 UTXO 위에 메타데이터를 탑재하여 스마트 컨트랙트를 구현. 이더리움의 계정 모델이 아닌, UTXO 확장 방식.

UBMS::S_UTXO.ubms 필드:
  meta     메타데이터 (온체인 저장)
  ttl      유효기간 (만료 시 자동 소멸)
  조건실행  조건부 UTXO 잠금/해제

온체인/오프체인 혼합 실행 모델:

  • 온체인: 조건 실행, TTL, 메타데이터 저장

  • 오프체인: 복잡한 연산은 외부에서 처리 후 결과만 온체인 기록