UBMS 기술 분석 보고서
UTXO-Based Metadata Smart Chain
작성자: 한혁진 (bokkamsun@gmail.com)
작성일: 2026년 3월 1일
본 보고서에 대하여
UBMS는 2024년 11월에 개발을 시작하여 현재까지 활발히 개발이 진행 중인 프로젝트.
가운영 환경에서 실제 데이터를 축적하면서 그 피드백을 바탕으로 설계를 다듬고 코드를 개선하는,
살아 있는 프로젝트.
운영은 단계적으로 진행:
베타 테스트 2025년 6월 종료 됨, 외부 참여자 확대
가운영 (현재) 가운영 환경에서 실제 데이터 수집, 각종 장애 경험 축적
정식 운영 가운영 피드백 반영 소스코드 완성 후 전환
가운영 기간 동안 포럼을 운영하여 참여자와 직접 소통하며,
다양한 장애 상황을 의도적으로 경험하고 대응 코드를 작성하는 방식으로 안정성을 확보하고 있다.
가운영 중 발견되는 개선점은 즉시 수집되고, 이 과정에서 축적되는 실측 데이터가
경제 모델(Shifted Sigmoid, PoB, 동적 수수료)의 설계 검증 근거가 되고,
실제로 많은 피드백을 받고 코드에 지속적으로 반영되고 있다.
본 보고서가 분석한 코드는 브랜치 v5 기준으로, 전체 설계의 약 40%에 해당하는 골격 완성 단계.
핵심 아키텍처와 주요 모듈의 동작이 확인된 부분만을 대상으로 기술 분석을 수행했으며,
아직 구현 중이거나 내부 테스트 단계에 있는 기능은 본 보고서의 분석 범위에 포함되지 않는다.
다시 말해, 이 보고서에 담긴 것은 완성된 부분의 기술력이고,
이 프로젝트는 장기 프로젝트로, 본 보고서의 분석 범위를 넘어서는 규모로 계속 성장해 나갈 것이다.
완성된 제품의 기술 보고서는 결과물을 설명할 뿐이지만,
40% 시점의 보고서는 이 프로젝트가 어디를 향해 가고 있는지,
어떤 설계 철학과 기술적 지향점 위에 서 있는지를 보여 준다.
코드의 골격이 곧 설계자의 의도이며, 완성형의 윤곽은 충분히 알 수 있다.
현재는 1인 개발 체제이나, 프로젝트가 성장함에 따라 팀 확장을 통해
외부 코드 리뷰, 보안 감사, 자동화 테스트 체계를 보강할 계획이다.
1. 프로그램 개요
UBMS(UTXO-Based Metadata Smart Chain)는 100% 독자 개발된 한국형 블록체인 풀노드 시스템.
C++20 표준으로 작성되었으며, UTXO 모델 위에 메타데이터 기반 스마트 컨트랙트를 구현.
핵심 특징:
- PoW + PoS + PoB 하이브리드 합의 알고리즘
- PSAN (역할 다형성 자율 조정 네트워크) 아키텍처
- Shifted Sigmoid 알고리즘 기반 스테이킹 보상 분배
- 결정론적 2D 격자 기반 다중경로 라우팅 (특허 기술)
- Linux io_uring 기반 고성능 비동기 I/O
- 3계층 캐시 구조로 조회 성능 극대화
- 비콘 체인 없는 완전 분산형 합의
총 발행량: ~21,000,000 UBMS, 소수점 8자리 (mensch 단위 = 100,000,000)
블록 보상 분배: 채굴자(Miner) 5% + 스테이커(Staker) 95% 온체인 자동 분배
2. 모듈 구조
ubmscoin/
src/
libubmstype.so 타입 정의, JSON/바이너리 직렬화 엔진
libubmslog.so 파일 기반 로깅
libubmsutil.so Worker 템플릿, 스레드 안전 큐, 산술 오버플로 방지, 변환 유틸
libubmscrypto.so RSA-4096, SHA256, RIPEMD160, Base58, AES-GCM, zlib 압축
libubmsio_uring.so io_uring 기반 서버/클라이언트, WebSocket, 세션 관리
libubmsevent.so libevent 기반 이벤트 엔진, 신호-슬롯, OS 시그널 통합
libubmstopol.so 결정론적 2D 격자, 3경로 라우팅, 지향성 가십, 독자 DHT
libubmshttp.so REST API + 리버스 프록시 + 리다이렉트 + 레이트 리미팅
libubmscoin.so 블록체인 핵심 (블록, TX, UTXO, 캐시, DB, 검증)
ubmsdaemon 데몬 진입점, P2P 허브, 워커 스레드들
ubmsnotify 독립 실행 FCM 푸시 알림 서버 (라이브러리 범용성 실증)
의존 관계:
libubmstype.so (기반)
libubmslog.so
libubmsutil.so (Worker, QueueSafe, Arith, Convert)
libubmscrypto.so (RSA, SHA256, Base58, zlib)
libubmsio_uring.so (io_uring 서버/클라이언트)
libubmsevent.so (이벤트 루프, 신호-슬롯)
libubmstopol.so (독자 DHT, 토폴로지)
libubmshttp.so (REST API)
libubmscoin.so (블록체인 핵심)
ubmsdaemon (데몬 + P2P)
ubmsnotify (독립 실행 푸시 알림 서버, 라이브러리 범용성 실증)
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) = \frac{1}{1 + e^{-z}}$$
$$z = \left(\frac{x + s}{T} - 0.5\right) \times 10$$
x : 해당 스테이커의 스테이킹 수량
T : 전체 스테이커 스테이킹 합계
r = 0.2 (좌측 이동 비율)
s = T × r (이동값)
10을 곱해 소지분과 대지분 간 격차를 유의미하게 증폭
개별 스테이커 보상 공식
$$\text{reward}(x) = (\text{block reward} \times 95\%) \times \frac{R(x)}{\sum R(x_i)}$$
$$z = \left(\frac{x + T \times 0.2}{T} - 0.5\right) \times 10$$
보상 분배 구조:
블록 보상 분배:
채굴자: 블록 보상의 5% ← PoW
스테이커: 블록 보상의 95% ← PoS (Shifted Sigmoid 비율로 분배)
효과:
- 대지분 독식 방지 — 보상이 선형이 아닌 곡선화되어 고지분자가 급격히 독식 불가
- 소지분 참여자 보정 — 적은 지분도 의미 있는 보상 획득 → 지속적 참여 유도
- 수학적 정당성 — 시프트된 Sigmoid는 정규화 후에도 전체 보상 총합 유지
3.3.1 소각 메커니즘 (Burn Mechanism)
PoS 보상 분배 시 참여 노드 수가 적을 때 일부 보상을 자동 소각(Burn)하는 공급 조절 메커니즘이 내장되어 있다.
$$\text{PoS 분배율} = \max(0.01,\;\min(1,\;\tfrac{N}{10{,}000})) \times 100\%$$
$$\text{PoS 소각률} = \Big(1 - \max(0.01,\;\min(1,\;\tfrac{N}{10{,}000}))\Big) \times 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)
─────────────────────────────────────────────
$$C_1 = \sum C_{1i} = 1{,}012{,}500 \;\text{UBMS}$$
후반 채굴 단계
블록 생성 시간: 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)
─────────────────────────────────────────────
$$C_2 = \sum C_{2j} \approx 20{,}000{,}000 \;\text{UBMS}$$
총 발행량 요약
$$\text{총 발행} = C_1 + C_2 = 1{,}012{,}500 + 20{,}000{,}000 \approx 21{,}012{,}500 \;\text{UBMS}$$
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 = \sqrt{\frac{v}{v_0}} = \sqrt{\frac{v}{10{,}000}}$$
$$F = B \times EF \times CF = 1{,}000 \times \sqrt{\frac{v}{10{,}000}} \times 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, 메타데이터 저장
- 오프체인: 복잡한 연산은 외부에서 처리 후 결과만 온체인 기록
4. PSAN 네트워크 아키텍처
PSAN(Role-Polymorphic Self-Adjusting Network, 역할 다형성 자율 조정 네트워크)은 UBMS의 P2P 네트워크 설계 철학.
핵심 원리
1. 역할 다형성: 하나의 노드가 릴레이/투표자/채굴자 역할을 동적으로 수행
2. 자율 조정: 네트워크 규모에 따라 BP(Blueprint) 수를 자동 산출
3. CF 완화: 메시지 플러딩 방지, 결정론적 경로로 대역 낭비 제거
BP(Blueprint) 계산 공식 (백서 인용)
$$R = \max\!\Big(3,\;\lfloor \log_2(N) \,/\, 2 \rfloor \times 2 + 1\Big)$$
$$V = \max\!\Big(5,\;\lfloor \log_2(N) \,/\, 1.2 \rfloor \times 2 + 1\Big)$$
N = 전체 노드 수, 항상 홀수로 설정하여 다수결 명확화
노드 수별 BP 예시
100개 노드: log₂(100) ≈ 6.64 → R = 3, V = 11
1,000개 노드: log₂(1000) ≈ 9.96 → R = 5, V = 21
10,000개 노드: log₂(10000) ≈ 13.28 → R = 7, V = 51
100,000개 노드: log₂(100000) ≈ 16.61→ R = 11, V = 101
최소 합의 요건
릴레이 노드 3개 이상
투표 노드 5개 이상
채굴 노드 1개 이상
합계 최소 9개 노드로 합의 가능
비콘 체인 없는 완전 분산형 합의:
별도의 비콘 체인이나 중앙 코디네이터 없이
노드 간 직접 투표로 합의를 달성함
4.1 스레딩 모델
메인 스레드
UBMS::EventBase (신호 처리)
P2P 허브
UBMS::UringPool (CPU 코어 수만큼 스레드)
UBMS::ServerBinP2P (인바운드 P2P)
UBMS::ServerWeb (웹소켓)
워커 스레드들 (각각 독립 큐 보유)
UBMS::DecodeWorker (바이너리 프레임 디코딩)
UBMS::SendWorker (메시지 직렬화 + 전송)
UBMS::NodeWorker (피어 관리, 토폴로지)
UBMS::ChainWorker (블록 채굴, 검증, 동기화)
UBMS::TxWorker (트랜잭션 전파)
UBMS::HttpWorker (REST API)
4.2 메시지 흐름
수신:
UBMS::ServerBinP2P::onRead (UBMS::UringPool 스레드)
-> DecodeWorker 큐에 push
-> 32바이트 메시지 ID 중복 확인
-> 평문 해제 또는 복호화
-> p2p::execPlain/execCrypto (라우팅)
-> NodeWorker / ChainWorker / TxWorker 큐에 push
전송:
워커에서 UBMS::SendWorker::sendToOutbound() 호출
-> 직렬화 + 압축(평문) 또는 암호화
-> 32바이트 메시지 ID 생성
-> UBMS::ClientBinP2P::sendMessageBinary()
4.3 P2P 프로토콜
메시지 구조 (UBMS::S_MESSAGE):
messageId 32바이트 해시
header 명령 식별자 (REQUEST_INIT, VOTE_BLOCK, ADD_BLOCK 등)
type 페이로드 타입
payload 직렬화된 데이터
ttl 가십 전파 수명 (기본값 5)
priority 우선순위
path 라우팅 경로
피어 핸드셰이크:
아웃바운드 연결 -> REQUEST_INIT(평문) -> RESPONSE_INIT(평문)
-> REQUEST_PEER_LIST(암호) -> RESPONSE_PEER_LIST(암호)
-> 토폴로지 구성
가십 3가지 모드:
GOSSIP 무작위 5개 피어에 전파 (전통 가십, 보조용)
TTL=5, XOR 모듈러2 기반 피어 거리 계산
GOSSIP_PATH 경로 내장형 전달 (3경로: 최단 + 좌편향 + 우편향)
메시지에 path[]를 싣고 다음 노드 한 칸만 전진
루프 구조적 차단, 중간 판단 불필요
GOSSIP_DIR 지향성 가십 (결정론 격자 기반 부채꼴 전파)
방향 벡터 u=(sx,sy)를 메시지에 내장
전방 이웃만 선택 (delta dot u > 0)
팬아웃 최대 3, TTL = max(3, floor(0.8 * 대각선))
4.4 합의 흐름 (PoW + PoS + PoB 하이브리드)
RESET (라운드 초기화)
-> REQUEST_MINE_INFO (TX 목록 수집)
-> MINE (PoW: 블록 생성, 난이도 충족 해시 탐색)
-> DISTRIBUTE_BLOCK (PSAN 경로로 검증자에게 전달)
-> VOTE_BLOCK (PoS: 스테이커 검증자가 투표)
-> VOTE_BLOCK_AGREE (70% 이상 승인, BFT 2/3 기준 + 안전 여유)
-> ADD_BLOCK (체인에 추가)
+-> 채굴자 보상 5%
+-> 스테이커 보상 95% (Shifted Sigmoid 분배)
+-> TX 수수료 -> 5단계 유통인 분배 (PoB: 60/20/10/7/3%)
-> 새 RESET
블록 부족 시:
REQUEST_BLOCK -> RESPONSE_BLOCK -> ACCEPT_RESPONSE_BLOCK
-> 높이가 따라잡으면 정상 모드 전환
5. 검증 체계
UBMS::InspectManager가 9개의 세부 검증기를 통합 관리.
UBMS::InspectTx TX 구조 검증
UBMS::InspectUtxo UTXO 유효성
UBMS::InspectBlock 블록 해시, 이전해시, 머클루트, 난이도, 타임스탬프
UBMS::InspectInput 입력 유효성
UBMS::InspectSpent UTXO 소비 여부
UBMS::InspectStake 스테이크 검증
UBMS::InspectReferral 추천인 검증
UBMS::InspectBalance 잔액 검증
UBMS::InspectSignature 서명 검증
서명 중복 방지: 최근 서명을 윈도우 기반으로 추적.
Inspector (감사 도구):
buildReport()로 주소별 종합 감사 실행
- UTXO 스냅샷 vs DB 일치성
- 마이닝 보상 테이블 검증
- 전체 블록 리플레이 시뮬레이션
- 이중 지불 탐지
6. 기반 라이브러리 특징
6.1 io_uring 비동기 I/O (libubmsio_uring.so)
Linux io_uring을 직접 래핑한 고성능 I/O 엔진.
libevent의 bufferevent를 대체하며, 훨씬 적은 시스템콜로 동일 작업을 수행.
핵심 최적화:
Multishot Accept/Recv SQE 재등록 없이 연속 수신
Zero-Copy Send 커널이 직접 버퍼 참조, 메모리 복사 제거
Provided Buffer Ring 커널 관리 버퍼 풀, 할당 비용 제거
Fixed FD fd 사전 등록, 조회 비용 제거
Batch Submit 여러 SQE를 한 번에 제출
Backpressure 수신/송신 큐 크기 제한으로 메모리 안정성
세대 번호(gen)로 stale CQE 감지: 연결이 끊긴 후 뒤늦게 도착하는 완료 이벤트를 안전하게 무시.
UBMS::UringSession이 per-fd 상태를 관리하며, 참조 카운팅(incRef/decRef)으로 안전하게 해제.
6.2 libevent 기반 이벤트 아키텍처 — Qt/Boost 없는 독자 설계
UBMS는 Qt의 시그널/슬롯, Boost.Asio의 이벤트 루프, Boost.Signals2의 옵저버 패턴을
libevent 하나로 전부 대체했다. 외부 GUI 프레임워크나 대형 라이브러리 의존 없이,
libevent의 이벤트 루프를 기반으로 6가지 영역에 걸쳐 독자적인 이벤트 시스템을 구축.
6.2.1 이벤트 루프 엔진
libevent의 event_base를 독립 스레드로 구동하는 래퍼.
EVLOOP_NO_EXIT_ON_EMPTY 플래그로 이벤트가 없어도 루프가 유지되며,
event_base_loopbreak로 안전하게 종료. 이것이 UBMS 전체 이벤트 시스템의 심장.
UBMS::EventBase
event_base_new() 이벤트 루프 생성
event_base_loop() EVLOOP_NO_EXIT_ON_EMPTY로 상주 구동
event_base_loopbreak() 안전 종료
evthread_use_pthreads() 멀티스레드 안전성 활성화
6.2.2 신호-슬롯 시스템 — libevent를 비동기 디스패처로 응용
Qt의 시그널/슬롯을 libevent 위에 재구현. 핵심 아이디어는 event_new로 타이머 이벤트를 만들되
timeval{0,0}으로 즉시 발화시켜, 이벤트 루프가 슬롯 콜백을 비동기 디스패치하게 만드는 것.
사용 예시:
// connect: 슬롯 등록 (weak_ptr로 수명 안전)
signal.connect(instance, "onBlock", &Handler::onNewBlock);
// emit: libevent 이벤트 큐에 즉시 예약, 이벤트 루프가 콜백 실행
signal.emit(instance, "onBlock", blockData);
emit 내부 동작:
1. COW 슬롯 스냅샷 획득 (shared_ptr 참조만 복사, 벡터 복사 제거)
2. EmitEvent 구조체 생성 (args + 슬롯 스냅샷 + 인스턴스)
3. event_new(base, -1, EV_TIMEOUT, cb_emit, emitEvent) 으로 libevent 이벤트 등록
4. event_add(ev, timeval{0,0}) 으로 즉시 발화 예약
5. 이벤트 루프 스레드에서 cb_emit이 슬롯 스냅샷을 순회하며 콜백 실행
안전성 설계 — 5중 방어:
weak_ptr 캡처 소멸된 객체에 콜백하지 않음 (UAF 방지)
COW 슬롯 벡터 emit 중 connect/disconnect 안전 (락프리 읽기)
3단계 상태 머신 Alive -> Marked -> Cleaning (CAS 전이, 재진입 방지)
m_cbCount 원자 카운터 소멸자가 진행 중 콜백 완료를 대기 (UAF 이중 방지)
event_base_once 정리 Marked 이벤트를 이벤트 루프에서 안전하게 지연 해제
Qt의 시그널/슬롯은 MOC 코드 생성기가 필요하고, Boost.Signals2는 헤더 비대로 컴파일 시간이 증가함.
UBMS의 신호-슬롯은 순수 C++ 템플릿만으로 타입 안전한 비동기 신호-슬롯을 구현하며,
외부 코드 생성 도구가 불필요.
신호 관리자가 type_index 레지스트리로 전역 신호를 관리하여,
모듈 간 직접 참조 없이 느슨한 결합을 달성.
6.2.3 HTTP 서버 (libubmshttp.so) — libevent의 evhttp 기반 REST API
libevent의 evhttp를 기반으로 완전한 REST API 서버를 구축.
자체 이벤트 루프 스레드에서 독립 동작하며, 런타임 재바인딩(rebind)을 지원.
UBMS::Http 자체 UBMS::EventBase 소유, 독립 스레드 HTTP 서버
UBMS::Router method+URI 기반 라우팅 테이블 (shared_mutex 보호)
addRoute: 외부 접근 가능 엔드포인트
addLocal: 로컬 전용 엔드포인트 (관리 API 분리)
UBMS::Forwarder 리버스 프록시, FIXED/ROUNDROBIN 정책
path/query 유지, 로컬 요청 제외, prefix 필터링
UBMS::Redirector 301/302/307/308 리다이렉트, ROUNDROBIN 분산
브라우저 캐시 고려한 상태코드 선택 (307 임시 vs 308 영구)
UBMS::Abuse IP+URI별 요청 제한, LRU 캐시로 메모리 상한
UBMS::HttpRequest onPreRoute 훅으로 포워딩/리다이렉트 파이프라인 구성
요청 처리 흐름:
evhttp 요청 도착
-> Abuse 검사 (Rate Limiting)
-> onPreRoute (Redirector -> Forwarder 순서로 가로채기)
-> Router.route() (method+URI 매칭)
-> 핸들러 실행 -> sendResponse
이 구조로 단일 HTTP 서버가 REST API + 리버스 프록시 + 리다이렉트 + 레이트 리미팅을
라이브러리 단 하나(libevent)로 제공. nginx나 별도 프록시 서버 없이 노드 자체가 이 모든 기능을 수행.
6.2.4 OS 시그널 핸들링
POSIX 시그널(SIGINT, SIGTERM 등)을 libevent의 이벤트 루프에 통합함.
evsignal_new로 시그널을 이벤트로 변환하여, 비동기-안전하지 않은 작업도
이벤트 루프 스레드에서 안전하게 처리.
UBMS::SignalHandler _sigHandler;
_sigHandler.on(SIGINT, [](int){ g_running.store(false); });
_sigHandler.on(SIGTERM, [](int){ g_running.store(false); });
_sigHandler.start(eventBase.getBase());
6.2.5 이벤트 루프 풀
이벤트 루프를 N개 생성하여 병렬 이벤트 처리를 지원.
io_uring 풀과 대칭 구조로, io_uring이 I/O를 담당하고 이벤트 루프 풀이 로직 이벤트를 담당하는
이중 이벤트 엔진 아키텍처를 구성.
6.2.6 설계 요약 — libevent 단일 라이브러리로 6가지 역할
| 역할 | libevent API | 대체 대상 |
| 이벤트 루프 엔진 | event_base_loop | Boost.Asio io_context |
| 비동기 신호-슬롯 | event_new + EV_TIMEOUT | Qt signal/slot, Boost.Signals2 |
| HTTP REST 서버 | evhttp | nginx, Express, Flask |
| 리버스 프록시 | evhttp + libcurl | nginx proxy_pass |
| OS 시그널 통합 | evsignal_new | 직접 signal() 호출 |
| 타이머/주기 이벤트 | event_add + EV_PERSIST | 별도 타이머 라이브러리 |
Qt(~50MB), Boost(~150MB 헤더) 같은 대형 의존성 없이, libevent(~1MB) 하나로
GUI 프레임워크급 이벤트 시스템과 웹 서버 기능을 모두 구현함.
이는 빌드 시간 단축, 배포 크기 최소화, 크로스 컴파일 용이성에 직접적으로 기여.
6.2.7 ubmsnotify — 라이브러리 범용성의 실증
ubmsnotify는 UBMS 블록체인의 독립 실행 응용 프로그램.
메인 노드(ubmsdaemon)와 별도 프로세스로 동작하며, 블록 이벤트를 실시간으로 수신하여
모바일 디바이스에 FCM 푸시 알림을 전송.
이 프로그램이 기술적으로 중요한 이유는 — libubmsevent.so, libubmsio_uring.so가
블록체인 노드 전용이 아니라 범용 서버 애플리케이션 프레임워크로 동작함을 실증하기 때문.
ubmsnotify의 아키텍처:
ubmsnotify (독립 실행 바이너리)
UBMS::EventBase libevent 이벤트 루프 (libubmsevent.so)
UBMS::SignalHandler SIGINT/SIGTERM 안전 처리 (libubmsevent.so)
UBMS::UringPool io_uring 기반 네트워크 I/O (libubmsio_uring.so)
WebSocket 서버 모바일 클라이언트 접속 수신 (libubmsio_uring.so)
WebSocketClient 외부 블록체인 노드 구독 (libubmsio_uring.so)
WorkQueue 단일 워커 스레드 + 1초 주기 틱 (자체 구현)
FcmSender Google FCM HTTP v1 API (libcurl + OpenSSL)
ConsoleView 터미널 대시보드 (fmt::color + ANSI escape + ioctl 터미널 감지)
동작 흐름:
1. WebSocket 서버로 모바일 앱 접속 수신, FCM 토큰 + 지갑 주소 등록
2. WebSocketClient로 블록체인 노드에 WSS 연결, 새 블록 구독
3. 블록 도착 시 TX/스테이크 보상에서 등록된 주소 매칭
4. 매칭된 주소의 FCM 토큰으로 푸시 알림 전송
5. 토큰 자동 갱신, NOT_FOUND 토큰 자동 제거, 외부 연결 자동 재접속
핵심 설계 특징:
스레드 안전성 모든 I/O 콜백이 WorkQueue.post()로 워커 스레드에 직렬화
데이터 보호용 mutex 불필요, 큐 조작용 mutex만 사용
자동 복구 FCM 토큰 만료 시 자동 갱신, 외부 노드 끊김 시 자동 재연결
리소스 관리 LRU 기반 토큰 맵, 유효하지 않은 토큰 자동 제거
이것이 입증하는 것:
libubmsevent.so (UBMS::EventBase + UBMS::SignalHandler) 이벤트 루프 프레임워크로 독립 사용 가능
libubmsio_uring.so (UBMS::UringPool + WebSocket) 네트워크 서버 프레임워크로 독립 사용 가능
두 라이브러리 조합 범용 실시간 서버 애플리케이션 구축 가능
이 라이브러리들을 Ubuntu 패키지로 배포하면, 블록체인과 무관한 일반 서버 애플리케이션
(채팅 서버, IoT 게이트웨이, 실시간 모니터링 서버 등)에도 그대로 활용할 수 있다.
블록체인 프로젝트가 범용 인프라 라이브러리를 자체 생산한 사례로,
이는 프로젝트의 기술적 깊이를 넘어 산업적 활용 가치를 보여준다.
6.3 암호화 (libubmscrypto.so)
RSA-4096 키 생성, 서명, 검증, 암호화
SHA-256 블록/TX 해싱
RIPEMD-160 주소 생성 (독립 구현, OpenSSL 의존 없음)
Base58Check 비트코인 호환 주소 인코딩
AES-GCM 세션 암호화 (진행 중)
HMAC-SHA256 메시지 인증
zlib 메시지 압축 (Zip Bomb 방어: 64MB 제한)
OpenSSL 3.x의 EVP API를 사용하고, default + legacy provider를 모두 로드.
향후 계획: 타원곡선 암호(ECDSA/Ed25519)를 추가하여 서명 크기와 키 생성 속도를 개선하고,
양자내성 암호(PQC) 알고리즘 도입을 위한 OpenSSL 3.x의 provider 구조를 활용할 예정.
6.4 독자 직렬화 엔진 (libubmstype.so)
libubmstype.so는 UBMS의 모든 데이터 구조의 기반이 되는 독자 개발 직렬화 프레임워크.
// 실제 UBMS::S_UTXO의 describe() — 이것만으로 JSON + 바이너리 직렬화가 자동 생성됨
void UBMS::S_UTXO::describe() {
reg("index", index);
reg("amount", amount);
reg("timestamp", timestamp);
reg("owner", owner);
reg("txid", txid);
regStruct("stake", stake); // S_STAKE 재귀 직렬화
regStruct("ubms", ubms); // S_UBMS 재귀 직렬화
}
Serial 계층 (리틀엔디안 바이너리 코덱):
UBMS::Serial::writeUInt64/readUInt64 8바이트 리틀엔디안
UBMS::Serial::writeString/readString 길이 접두 문자열
UBMS::Serial::writeVector/readVector 템플릿 특수화 벡터
→ 벡터 크기 상한으로 OOM 공격 방어
→ 남은 버퍼 크기 검사로 버퍼 오버리드 방지
안전 역직렬화 설계:
- 버퍼 경계 초과 시 나머지 필드 건너뛰기 (부분 객체 안전 생성)
- enum 값 범위 벗어나면 fallback 값으로 복원
- JSON 타입 불일치 시 필드 무시 (크래시 방지)
- 벡터 크기 상한 + 남은 버퍼 대비 검사
6.5 토폴로지 (libubmstopol.so) - 결정론적 2D 격자 + 지향성 가십
이 모듈은 특허 출원된 독자 기술.
핵심 아이디어: 모든 피어를 같은 시드로 같은 바둑판에 배치하고, 그 위에서 경로를 계산.
6.5.1 결정론적 격자 배치
1. 각 피어의 IP와 시드로 HMAC-SHA256 해시를 계산
2. 해시값 4등분 후 XOR로 합쳐서 임계값(threshold) 생성
3. (임계값, IP) 쌍으로 오름차순 정렬
4. 정렬 순서대로 S x S 격자에 순차 배치 (S = ceil(sqrt(N)))
5. 좌표: r = i / S, c = i % S
$$h_p = \text{LOW}_w\!\big(\,F(\text{seed}) \oplus F(\text{ip}(p))\,\big)$$
정렬 키 = (h_p, ip) 오름차순
6.5.2 최단경로 탐색 알고리즘 — 직진 우선 BFS
2D 격자 위에서 출발 노드(start)와 목적 노드(goal)를 잇는 최단 경로를 찾는 것이
경로 전파 방식(GOSSIP_PATH)의 핵심임.
UBMS는 일반적인 BFS를 격자 특성에 맞게 확장한 직진 우선 BFS(Straight-First BFS)를 사용.
그래프 모델링:
격자 S × S 위의 각 셀이 노드이고, 8방향 이웃이 간선(모두 가중치 1)임.
상하좌우 4방향 + 대각선 4방향 = 최대 8개 이웃.
경계 셀은 이웃 수가 줄어들고, 빈 셀(피어 미배치)은 건너뜀.
알고리즘 상세 (shorPathIndex):
입력: 시작 인덱스 s, 목표 인덱스 g
출력: s → g 최단 경로 (노드 인덱스 배열)
1. 초기화
dist[N] = -1 (미방문), prev[N] = -1 (부모 없음)
pdx[N], pdy[N] = 0 (각 노드 도달 시 진입 방향 기록용)
dist[s] = 0, 큐에 s 삽입
2. BFS 루프
큐에서 u를 꺼냄
u == g이면 즉시 종료
u의 8이웃 목록을 구한 뒤, 탐색 순서를 정렬:
정렬 규칙 1: 직선 이동 우선
상·하·좌·우(축 정렬) 이웃을 대각선 이웃보다 먼저 탐색
정렬 규칙 2: 직진 우선 (방향 연속성)
부모→u 진입 방향과 u→v 방향이 같으면 우선 탐색
(= 꺾이지 않고 직진하는 경로를 선호)
정렬된 순서대로 이웃 v를 방문:
미방문이면 dist[v] = dist[u] + 1, prev[v] = u
v 도달 방향 (u→v)을 pdx[v], pdy[v]에 저장
v == g이면 prev 체인을 역추적하여 경로 반환
아니면 큐에 v 삽입
3. 경로 복원
prev[g] → prev[prev[g]] → ... → s 역추적 후 reverse
직진 우선이 중요한 이유:
일반 BFS는 같은 거리의 경로 중 아무거나 반환함.
격자에서는 지그재그 경로와 직선 경로가 동일 거리일 수 있음.
예시 (5×5 격자, A→B):
일반 BFS: A → ↘ → → → ↗ → B (지그재그, 같은 홉)
직진 우선: A → → → → → B (직선, 같은 홉)
직선 경로가 메시지 전파에 유리:
- 중간 노드의 포워딩 방향 판단이 일관됨
- 편향 경로(P+, P-)와의 경로 분리가 명확해짐
- 3경로 간 겹침(overlap)이 최소화됨
8이웃 탐색과 체비셰프 거리:
격자에서 8방향 이동 시 최단 거리는 체비셰프 거리(Chebyshev distance):
d_cheb(A, B) = max(|Δr|, |Δc|)
대각선 이동 1칸 = 수직 1칸 + 수평 1칸을 한 번에 소화
따라서 BFS 홉 수 = max(|r₁-r₂|, |c₁-c₂|)
100×100 격자(10,000 노드)에서 최악 거리 = 99홉
평균 거리 ≈ 66홉
복잡도:
시간: O(N) — 각 노드 최대 1회 방문, 이웃 정렬은 O(8 log 8) = O(1)
공간: O(N) — dist, prev, pdx, pdy 배열
N = 격자 내 노드 수
6.5.3 3경로 라우팅 (최단 1 + 좌우 편향 2)
최단경로 BFS를 기반으로, 3개의 독립 경로를 생성하여 메시지 전달 신뢰성을 확보.
경로 P0: BFS 최단 경로 (직진 우선 8이웃 무가중 그래프)
경로 P+: 좌측 편향 경로 (중간점을 왼쪽으로 밀어서 우회)
경로 P-: 우측 편향 경로 (중간점을 오른쪽으로 밀어서 우회)
편향 경로 생성 과정 (Affine Waypoint):
편향 경로는 단순히 BFS를 두 번 호출하되, 중간 경유지(waypoint)를 아핀 변환으로 생성.
편향 경로 생성 단계:
1. 진행 벡터 d = (goal.c - start.c, goal.r - start.r)
2. 진행 거리 L = ‖d‖ = hypot(Δc, Δr)
3. 진행각 θ = atan2(Δr, Δc)
4. 직선 중간점(t=0.9 지점)을 로컬 프레임으로 변환
[x_L, y_L] = R(-θ) × (t·Δc, t·Δr) ← 역회전: 진행축을 x축에 정렬
5. 법선(y축) 방향으로 편향 적용
α = k × L × 0.2 ← 휨 세기 (거리에 비례)
y_L += α ← 로컬 y축으로 밀어냄
6. 월드 좌표로 복귀
[dC, dR] = R(θ) × (x_L, y_L) ← 정회전으로 원래 방향 복원
mid = start + (dC, dR) ← 절대 좌표
7. 격자 스냅 + 경계 클램프
mid = snapClamp(mid) ← 부동소수 → 정수 셀, 격자 내 보정
8. 빈 셀 보정
mid 셀에 피어가 없으면 반경 3 이내에서 가장 가까운 유효 셀 채택
$$\theta = \text{atan2}(\Delta r,\;\Delta c)$$
$$\alpha = k \times \|\vec{d}\| \times 0.2$$
$$\hat{n} = [-\sin\theta,\;\cos\theta]$$
$$p_m = p_s + t \cdot \vec{d} \;\pm\; \alpha \cdot \hat{n} \qquad (t = 0.9)$$
최종 경로 합성:
P+ = BFS(start → mid+) ⊕ BFS(mid+ → goal)
P- = BFS(start → mid-) ⊕ BFS(mid- → goal)
아핀 변환 적용 순서 (OpenGL의 SRT 행렬곱 순서와 동일):
S (Shear) : 법선 방향 휨 적용 (α만큼 밀어냄)
R (Rotate) : 진행각 θ로 회전/역회전
T (Translate): 시작점 좌표로 평행이동
순서: 로컬 변환(역회전 → 휨 적용 → 정회전) → 절대 좌표 이동
이 순서가 뒤바뀌면 중간점이 격자 밖으로 벗어남
경로 분리 보장:
t = 0.9로 설정하여 중간점이 목적지의 90% 지점에 위치
→ 출발~중간점 구간에서 최단경로(P0)와 겹칠 확률이 극히 낮음
→ 3경로가 격자 위에서 부채꼴 형태로 펼쳐져 독립성 확보
+k (좌측)와 -k (우측)를 대칭 적용하므로
P+와 P-는 P0 기준 양쪽으로 갈라짐
6.5.4 지향성 가십 (Directional Gossip)
1. 발신 노드가 이웃에게 보낼 때 방향 벡터 u = (sx, sy)를 메시지에 내장
2. 수신 노드는 8이웃 중 "전방 이웃"만 선택해서 전달
전방 조건: δ · u > 0 (이동벡터와 방향벡터의 내적이 양수)
3. 팬아웃 최대 3
4. TTL = max(3, floor(0.8 × D + 0.5)), D = sqrt((S-1)² + (S-1)²)
성능 비교 (N=10,000 노드, S=100):
총 전송 수 지연 재현성
최단경로 전파: ~100 O(√N) 결정론적
경로 3개 전파: ~336 O(√N) 결정론적
지향성 가십: ~30,000 O(√N) 결정론적
전통 가십: ~399,000 O(log N) 비결정적
6.5.5 운용 전략
평시: 경로 3개로 전역 신호 전달 (대역 최소)
장애시: 지향성 가십 보조 활성화 (커버리지 확보)
전통가십: 피크/중복 비용이 커서 상시 운용 비권장
6.5.6 독자 DHT 피어 관리 — 아웃바운드 전용 버킷
UBMS의 DHT는 Kademlia 프로토콜이 아닌 완전한 독자 설계.
이름만 DHT일 뿐 구조와 동작 방식이 근본적으로 다르다.
XOR 거리: SHA256(ip1) XOR SHA256(ip2)의 상위 64비트
버킷 구조: 고정 개수, log2(distance) 기반 분류 (Kademlia는 160개 k-bucket)
버킷 용도: 아웃바운드 전용 (연결할 대상 관리, 인바운드는 별도)
버킷 크기: Kademlia의 k=20 대비 대폭 확장
정렬 기준: XOR 거리 오름차순, 타이브레이커 ip 사전순
교체 정책: 가장 먼 피어 교체 (Kademlia는 가장 오래된 피어 유지)
COW 갱신: atomic shared_ptr로 버킷 전체를 스냅샷 교체
회전 엣지: Near/Far/Storage 3종 캐시, 20~30%씩 주기적 갱신
가십 중복: 해시셋 + FIFO 큐 (상한 제한)
Kademlia와의 핵심 차이:
Kademlia UBMS DHT
160개 k-bucket (비트별) 고정 개수 버킷 (log2 구간)
k=20 (버킷당 20개) 대폭 확장된 버킷 용량
양방향 (요청+응답) 아웃바운드 전용
가장 오래된 피어 우선 XOR 거리 가까운 피어 우선
FIND_NODE/STORE 프로토콜 격자 + 가십 + 회전 엣지 조합
핑-퐁 기반 활성 확인 client 유효성 직접 검사
버킷 수와 버킷 용량은 상수이며, 네트워크 규모에 따라 조정 가능.
독자 DHT에서 버킷은 피어 목록을 거리별로 분류하는 단순한 리스트이고,
특허 기술인 격자 라우팅과 지향성 가십이 메시지 전파의 핵심을 담당하므로
DHT는 피어 발견 보조 역할에 한정.
6.6 유틸리티 (libubmsutil.so)
UBMS::Worker<T> 템플릿: 큐 기반 워커 스레드의 공통 패턴.
push()로 작업 추가, process()에서 처리
callSync()로 워커 스레드에서 동기 실행 (promise/future)
60초 타임아웃 안전장치
UBMS::QueueSafe<T>: condition_variable 기반 스레드 안전 큐.
UBMS::Arith: uint64_t 오버플로/언더플로 검사. mulDiv()에서 uint128_t 중간값 사용.
7. 멀티스레드 안전성
7.1 락 전략
| 컴포넌트 | 락 타입 | 읽기 | 쓰기 |
| UBMS::CacheManager | shared_mutex | shared_lock (동시 다중) | unique_lock (배타적) |
| UBMS::Chain | mutex | - | addBlock/rollBack 직렬화 |
| UBMS::BlockCurrent | atomic shared_ptr + mutex | atomic load (락 없음) | mutex 보호 |
| UBMS::BlockMetaFullCache | atomic shared_ptr + mutex | atomic load (락 없음) | COW 교체 |
| UBMS::BlockPool | atomic shared_ptr + mutex | atomic load (락 없음) | COW 교체 |
| UBMS::VolatileCache | shared_mutex | shared_lock | unique_lock |
| UBMS::ConfirmedCache | shared_mutex | shared_lock | unique_lock |
| UBMS::TxCurrent | shared_mutex | shared_lock | unique_lock |
| DB | mutex | 모든 연산 직렬화 | 모든 연산 직렬화 |
7.2 TOCTOU 회피 설계
취약한 설계 (분리 호출):
Thread A: isSpentKey(key) → false (미소비)
--- 이 사이에 Thread B가 addBlock()으로 key 소비 ---
Thread A: addTx(key) → 이미 소비된 UTXO로 TX 생성 (이중 지불!)
UBMS의 해결: 원자적 검사 함수
checkDoubleSpendWithPool(address, key):
// CacheManager의 shared_lock이 이미 걸린 상태
// 1단계: 확정 원장 소비 확인
// TX풀 잔돈이면 통과, 아니면 거부
// 2단계: TX풀 소비 확인 (같은 주소)
// 이미 소비 예약되었으면 거부
// 3단계: 전역 크로스-주소 이중소비 확인
// 다른 주소의 TX가 이미 사용했으면 거부
// 전부 통과하면 미소비 확인 완료
원자적 검사 함수 전체 목록:
| 함수 | 검사 범위 | 용도 |
checkDoubleSpendWithPool() | 확정 + TX풀 + 전역 | 이중 지불 다단 검사 |
isNotSpentKeyWithPool() | 확정 + TX풀 잔돈 | 미소비 확인 |
getUTXOWithPool() | 확정 + TX풀 | UTXO 통합 조회 |
getInputWithPool() | DB + volatile + TX풀 | 입력 수집 |
getBalanceAvailableWithPool() | DB + volatile + TX풀 | 사용 가능 잔액 |
getStakeWithPool() | DB + volatile + TX풀 | 스테이크 통합 조회 |
락 계층 설계 (교착 방지):
UBMS::Chain::m_mutex (std::mutex, 배타적) ← addBlock/rollBack 직렬화
└→ UBMS::CacheManager::m_mutex (shared_mutex) ← 읽기/쓰기 분리
└→ UBMS::VolatileCache::m_mutex ← 내부 보호
└→ UBMS::ConfirmedCache::m_mutex ← 내부 보호
└→ UBMS::TxCurrent::m_mutex ← 내부 보호
규칙: 외부 → 내부 순서로만 취득, 역순 불가 (교착 원천 차단)
7.3 락프리 읽기 패턴
현재 블록, 블록 메타 전체캐시, 블록풀은 읽기 경로에서 잠금 없이 현재 상태의 스냅샷을 즉시 가져올 수 있도록 설계됨.
쓰기는 단일 경로로 제한하여 데이터 경합을 원천 차단하면서도, 읽기 쪽에 대기나 차단이 발생하지 않음.
7.4 TX풀 이중 소비 방지 — 4단 충돌 검사
isConflict_(reserved, tx):
검사 1: TX 내부 입력 중복
같은 TX 안에서 동일 UTXO를 두 번 참조하면 거부
검사 2: 주소별 예약 풀 이중 소비
같은 주소의 이전 TX가 이미 소비 예약한 UTXO면 거부
검사 3: 전역 크로스-주소 이중 소비
다른 주소의 TX가 이미 사용한 UTXO면 거부
→ m_globalSpentKeys (unordered_set, O(1) 조회)
검사 4: TX 내부 출력 인덱스 중복
같은 출력 인덱스를 두 번 생성하면 거부
TX풀 예약 풀 (UtxoPool) 동작:
applyReserveAdd_(tx):
output 중 자기 주소로 돌아오는 잔돈 → available에 추가
input → spent_keys + m_globalSpentKeys에 등록
효과:
A가 5 UBMS UTXO로 3 UBMS 전송 시
→ spent_keys: {원본 5 UBMS key}
→ available: {잔돈 2 UBMS key} ← 다음 TX에서 즉시 사용 가능
블록 확정 후 TX풀 정리 (3단계):
1) syncCurrentTx(confirmedTxList) → txid로 확정된 TX 제거
2) removeConflictingCurrentTx(spentKeys) → 충돌하는 미확정 TX 제거
3) cleanupCurrentTxByHeight(minHeight) → 너무 오래된 TX 제거
8. 성능 분석
이하 O() 표기는 시간 복잡도(Time Complexity)를 나타낸다. O(1)은 데이터 양과 무관하게 일정한 시간, O(N)은 데이터 양에 비례하는 시간을 의미.
8.1 조회 성능
| 연산 | 경로 | 비고 |
| 잔액 조회 | DB(owner 인덱스) + volatile 필터링 | O(UTXO 개수) |
| TX 존재 확인 | volatile(10블록) -> DB | 최신 TX는 메모리에서 즉시 |
| UTXO 소비 확인 | volatile spentKeys -> DB | O(10) 최대 |
| 최근 TX 조회 | volatile 역순 -> DB | txid 타임스탬프 정렬 |
| referral 조회 | ConfirmedCache 메모리 | O(1) 해시맵 |
8.2 쓰기 성능
| 연산 | 비용 | 비고 |
| 블록 추가 | O(TX수 + UTXO수) | volatile pushBack |
| DB 커밋 | O(차분 크기) | 10블록마다 한 번, 배치 쓰기 |
| 롤백 | O(1) | volatile popBack, DB 건드리지 않음 |
8.3 I/O 성능 — 실측 벤치마크
측정 환경: AMD Ryzen 7 2700X (2018년 출시), 싱글스레드 (1 core), 3초 측정, localhost
8년 전 CPU의 단일 코어만으로 측정한 수치. 동일 세대 Ryzen 9 3900X에서는 싱글코어 기준 30% 이상 향상 확인
처리량 — 텍스트 프로토콜
| 메시지 크기 | 클라이언트 | 처리량 (msg/s) | 송신 | 수신 |
| 32B | 1 | 1,195,757 | 3,587,433 | 3,587,271 |
| 32B | 10 | 10,132,692 | 60,851,192 | 30,398,077 |
| 256B | 1 | 883,132 | 2,649,581 | 2,649,396 |
| 256B | 10 | 4,284,165 | 27,230,564 | 12,852,496 |
| 1KB | 1 | 801,805 | 2,405,416 | 2,405,416 |
| 1KB | 10 | 1,628,376 | 8,246,630 | 4,885,129 |
| 4KB | 1 | 320,268 | 1,299,084 | 960,806 |
| 4KB | 10 | 205,166 | 1,706,216 | 615,498 |
처리량 — 바이너리 프로토콜
| 메시지 크기 | 클라이언트 | 처리량 (msg/s) | 송신 | 수신 |
| 32B | 1 | 1,431,783 | 4,295,670 | 4,295,349 |
| 32B | 10 | 9,755,885 | 74,314,915 | 29,267,656 |
| 256B | 1 | 1,231,194 | 3,693,694 | 3,693,584 |
| 256B | 10 | 5,260,272 | 31,169,940 | 15,780,817 |
| 1KB | 1 | 627,774 | 1,883,322 | 1,883,322 |
| 1KB | 10 | 1,709,745 | 8,647,578 | 5,129,235 |
| 4KB | 1 | 509,816 | 1,687,959 | 1,529,449 |
| 4KB | 10 | 447,800 | 2,172,084 | 1,343,400 |
레이턴시 (64B echo, 1,000회 반복)
| 지표 | 값 |
| 평균 | 32.0 us |
| p50 | 32.0 us |
| p99 | 38.1 us |
| min | 28.1 us |
| max | 40.6 us |
연결 속도
| 지표 | 값 |
| 연결 속도 | 12,419 conn/s |
| 총 연결 | 1,000건 / 0.08초 |
실측 수치 요약
위 벤치마크는 libubmsio_uring.so 자체 실측값이며, 타 라이브러리와의 동일 조건 비교 측정은 수행하지 않았다.
다만 싱글스레드에서 1KB 메시지 170만 msg/s, 32B 메시지 1,013만 msg/s, p99 레이턴시 38us는
io_uring의 커널 수준 최적화를 실용적으로 잘 활용한 결과이며,
공개된 epoll 기반 라이브러리(libevent, libuv, Boost.Asio 등)의 벤치마크 자료와 대조해도 상당히 높은 수치.
주요 실측 수치:
- 바이너리 1KB, 10클라이언트: 1,709,745 msg/s (싱글스레드)
- 텍스트 1KB, 10클라이언트: 1,628,376 msg/s (싱글스레드)
- 32B 소형 메시지, 10클라이언트: 10,132,692 msg/s
- p99 레이턴시: 38.1us (64B echo RTT)
- 연결 속도: 12,419 conn/s (1,000건/0.08초)
- 멀티코어 활용 시 추가 향상 확인 (사무실 장비에서 20%+ 향상)
io_uring 자체의 커널 수준 최적화(SQE 배치 제출, 커널 측 폴링, 시스템콜 감소)가 처리량의 주된 원인이며,
libubmsio_uring.so는 이 위에 multishot, zero-copy, provided buffers, backpressure를 조합하여
블록체인 노드에 적합한 네트워크 계층을 구성.
벤치마크 바이너리(ubmsio_uring_benchmark)가 빌드 산출물에 포함되어 있으므로,
위 수치는 누구든 동일 환경에서 직접 재현할 수 있다.
8.4 메모리 사용 추정
VolatileCache ~50MB (10블록 x 5MB/블록)
ConfirmedCache ~10MB (referral tree + nodeInfo)
TxCurrent ~100MB (pending TX + 예약 풀)
BlockPool ~100MB (미확정 분기)
합계 ~260MB (정상 상태)
DB 수 GB ~ 수백 GB (블록 데이터)
8.5 네트워크 최적화
메시지 압축 zlib (평문 메시지)
메시지 중복 제거 메시지 ID 해싱 + 윈도우 기반 중복 추적
공개키 캐싱 LRU 방식 (PEM 파싱 비용 제거)
배치 전송 sendmsg 일괄 전송
9. 보안 설계
9.1 빌드 보안
최상위 빌드 스크립트에서 보안 플래그를 전역 설정하여, 하위 11개 모듈 전체에 자동 적용.
컴파일러 보안
- 버퍼 오버플로우 런타임 탐지 — 표준 라이브러리 함수(memcpy, strcpy 등)의 버퍼 크기를 컴파일 타임에 파악하고, 런타임에 초과 시 프로세스를 즉시 중단
- 스택 카나리 강화 — 함수 프롤로그에 무작위 값(카나리)을 삽입하여, 스택 버퍼 오버플로우 공격이 리턴 주소를 덮기 전에 탐지. strong 모드는 배열이나 주소 참조가 있는 함수에 모두 적용
- 스택-힙 충돌 방지 — 스택을 한 번에 크게 키워서 힙 영역을 침범하는 Stack Clash 공격을 차단. 스택 확장 시 페이지 단위로 probe를 삽입하여 가드 페이지를 건너뛸 수 없게 한다
- 제어 흐름 무결성 — 간접 호출(함수 포인터, 가상 함수)과 리턴 주소를 하드웨어 수준에서 검증하여 ROP/JOP 공격을 차단. Intel CET(Shadow Stack + IBT)를 활용
- 위치 독립 코드 — 모든 코드를 PIC로 생성하여 ASLR(주소 공간 배치 무작위화)의 효과를 극대화. 공격자가 메모리 주소를 예측할 수 없게 한다
- 포맷 스트링 보안 — printf 계열 함수에서 사용자 입력이 포맷 문자열로 사용되는 경우를 경고가 아닌 컴파일 에러로 처리하여, 포맷 스트링 공격을 빌드 단계에서 원천 차단
- STL 컨테이너 범위 검사 — vector, string 등 STL 컨테이너의 인덱스 접근에 범위 검사를 활성화하여, 범위 초과 접근 시 즉시 abort
링커 보안
- Full RELRO — GOT(Global Offset Table)를 읽기 전용으로 설정하고, 프로그램 시작 시 모든 심볼을 즉시 resolve함. GOT 덮어쓰기를 통한 함수 하이재킹 공격을 차단
- 스택 실행 방지 — 스택 영역에 실행 권한을 제거하여, 스택에 주입된 셸코드가 실행되지 못하게 한다
- 텍스트 재배치 차단 — 코드 세그먼트에 쓰기 가능한 재배치를 금지하여, 공유 라이브러리의 코드 영역이 변조되지 않도록 보호
- 심볼 하이재킹 방지 — 여러 오브젝트에서 동일 심볼이 정의될 때 경고를 발생시켜, 악의적 심볼 교체를 탐지
릴리즈 빌드 추가 조치
- 디버그 심볼 제거로 바이너리 역분석 난이도 상승
- RPATH를 실행 파일 기준 상대 경로로 고정하여 라이브러리 경로 조작 방지
9.2 암호화 보안
RSA-4096 키 쌍 충분한 키 길이
SHA-256 이중 해싱 주소 생성 시
HMAC-SHA256 메시지 인증
Base58Check 체크섬으로 주소 오류 검출
Zip Bomb 방어 압축해제 64MB 제한
9.3 런타임 보안
Arith 오버플로 검사 금액 계산 시 uint64_t 범위 초과 방지
서명 중복 검사 윈도우 기반 서명 추적
TOCTOU 해소 이중 지불 원자적 검사
globalSpentKeys 크로스-주소 이중소비 차단
9.4 직렬화 안전성
libubmstype.so의 describe() 자기서술 패턴은 직렬화와 역직렬화를 동일한 선언에서 자동 생성함.
이로 인해 역직렬화 경로에서 발생할 수 있는 보안 위협이 프레임워크 수준에서 차단.
벡터 크기 상한 검사 비정상 크기 패킷에 의한 메모리 폭주 방지
버퍼 경계 검사 읽기 범위를 초과하는 접근 차단
enum fallback 처리 정의되지 않은 값에 대한 안전한 기본값 적용
수동 파싱 코드 제거 개발자 실수에 의한 역직렬화 취약점 원천 차단
P2P 환경에서 악의적 패킷이 유입되는 것을 전제로 설계되었으며,
대부분의 프로젝트에서 사후 패치로 추가되는 역직렬화 안전성이 여기서는 구조적으로 내장되어 있다.
9.5 테스트 인프라
모듈별 단위 테스트가 GTest 기반으로 구성되어 있으며, 약 5,800줄 규모의 테스트 코드가 존재.
현재 대규모 리팩토링 진행으로 일부 테스트가 갱신 대기 상태이며, 코드 안정화에 따라 순차적으로 복구 예정.
10. 설계 장점 요약
10.1 캐시 설계
- 3계층 캐시 + TX풀을 단일 잠금로 통합하여 원자적 상태 검사 보장
- 롤백이 O(1) (차분 popBack 한 번)으로, 비트코인 DisconnectBlock과 다른 접근
- 확정 데이터 커밋은 10블록마다 일괄 처리로 DB 쓰기 증폭 최소화
- 블록차분으로 변경분만 격리하여 원자적 적용/취소가 가능
- 소비 UTXO 사전수집으로 DB 이관 시 인덱스 고아 원천 방지
- owner/miner/txaddr 3종 인덱스로 주소별 조회 O(N) 달성
- TOCTOU 회피: 원자적 검사 함수 6종으로 이중지불을 구조적으로 차단
- TX풀 전역 소비키로 크로스-주소 이중소비 공격 O(1) 탐지
10.2 I/O 설계
- io_uring의 최신 기능(multishot, zero-copy, provided buffers)을 적극 활용
- 참조 카운팅 + 세대 번호로 비동기 환경에서 안전한 메모리 관리
- Backpressure 제어로 메모리 폭주 방지
10.3 동시성 설계
- 공유 잠금으로 읽기 다중화, 조회 병목 제거
- 공유 포인터 원자적 교체로 잠금 없는 읽기 (현재 블록, 블록풀 등)
- 워커 큐 패턴으로 각 기능이 독립 스레드에서 동작
- 신호-슬롯으로 모듈 간 느슨한 결합
10.4 데이터 설계
- UTXO 모델로 잔액 계산이 명확하고 검증이 용이
- describe() 기반 직렬화로 JSON/바이너리 이중 포맷 자동 지원
- owner/miner/txaddr 역인덱스로 주소별 조회 최적화
- txid가 타임스탬프 prefix라서 별도 시간 인덱스 없이 최신순 조회 가능
10.5 네트워크 설계 (특허 기술)
- 결정론적 2D 격자 배치로 모든 노드가 동일 토폴로지를 재현
- 아핀 편향 기반 3경로 라우팅으로 장애/혼잡/검열 내성 확보
- 지향성 가십으로 전통 가십 대비 전송량 1/13 수준으로 감소
- 전통 가십 대비 성능: 경로 전파 336 vs 전통 가십 399,000 (N=10,000)
- 독자 DHT(아웃바운드 전용 버킷)로 중앙 서버 없이 피어 발견
- 토폴로지 3초마다 재계산으로 네트워크 적응성
10.6 경제 설계 (토크노믹스)
- Shifted Sigmoid 곡선 보상으로 대형 스테이커 독식 방지, 소액 스테이커 공정 보장
- 채굴자 5% + 스테이커 95% 온체인 자동 분배
- PoB 5단계 유통인 수수료 분배 (60/20/10/7/3%)로 네트워크 성장 인센티브
- 동적 수수료: \(EF = \sqrt{v/v_0} \times CF\) — 외부 시장가 기반 합리적 수수료
- 소각(burn) 메커니즘: \(\max(0.01,\;\min(1,\;N/10{,}000))\)으로 공급 자동 조절
- 2단계 반감기 스케줄 (초반 540블록 급감소 + 후반 210,240블록 4년 주기)
11. 데이터 구조 핵심
UBMS::S_BLOCK (블록)
hash, previousHash, merkleHash, height, nonce, difficulty
transaction[], stakeReward[]
.
.
.
UBMS::S_TRANSACTION (트랜잭션)
type (NONE/LOCK/UNLOCK/REFERRAL)
txid, address, signature, publicKey
in[], out[], referral
.
.
.
UBMS::S_UTXO (미사용 출력)
txid, index, amount, owner
stake (NONE/LOCK/UNLOCK + minerAddress)
ubms (메타, TTL, 조건)
.
.
.
UBMS::BlockDelta (블록차분)
height, hash, previousHash
addedUtxo{}, spentKeys{}, spentUtxoInfo{}
transactions[], addedReferrals[]
.
.
.
12. 외부 의존성
| 라이브러리 | 용도 | 라이선스 | 비고 |
| OpenSSL 3.x | RSA, SHA, HMAC, 난수 | Apache 2.0 | EVP API |
| liburing | io_uring 시스템 인터페이스 | MIT / LGPL 2.1 | Linux 5.19+ |
| libevent | 이벤트 루프, 신호-슬롯, HTTP 서버, OS 시그널, 타이머 | BSD 3-Clause | Qt/Boost 전면 대체 |
| DB | 영구 KV 저장소 | BSD 3-Clause | Bloom filter |
| jsoncpp | JSON 파싱 | MIT | |
| fmt | 포맷 출력 | MIT | |
| zlib | 압축/해제 | zlib License | |
| libcurl | HTTP 클라이언트 | MIT/X inspired | FCM 알림용 |
12.1 라이선스 독립성 — 깨끗한 의존성 구조
블록체인 프로젝트에서 라이선스 문제는 간과하기 쉽지만, 상용화 단계에서 치명적인 장벽이 된다.
실제로 적지 않은 오픈소스 블록체인 프로젝트가 GPL, AGPL, SSPL 등
전염성(copyleft) 라이선스를 가진 라이브러리를 무분별하게 끌어다 쓰면서
라이선스 누더기가 되어 있다. 이 경우 프로젝트 전체가 해당 라이선스 조건에 종속되며,
상용 배포, 독점 라이선스 전환, 기술 라이선싱이 법적으로 불가능하거나 극도로 복잡해진다.
UBMS의 외부 의존성은 전부 허용적 라이선스(permissive license)로 구성:
Apache 2.0 상용 이용 자유, 특허 허가 포함
BSD 3-Clause 상용 이용 자유, 재배포 시 저작권 고지만 필요
MIT 사실상 무제한 사용
zlib License 거의 무제한, 출처 허위 표시만 금지
이 구성이 의미하는 것:
- 상용 배포 자유 — 소스 공개 의무 없이 바이너리 배포 가능
- 독점 라이선스 전환 가능 — 프로젝트 전체를 독점 소프트웨어로 전환 가능
- 기술 라이선싱 자유 — 특허 기술(격자 라우팅 등)을 제3자에게 라이선싱할 때 의존성 라이선스가 장애가 되지 않음
- 포크 위험 최소화 — GPL 전염에 의한 강제 소스 공개 위험 없다
특히 주목할 점은 Qt(LGPL/GPL/상용)와 Boost(BSL-1.0)를 의존성에서 완전히 제거한 것.
Qt는 LGPL 조건에서 동적 링킹 의무와 사용자 재링크 보장 등 까다로운 조건이 붙고,
상용 라이선스는 연간 수천 달러의 비용이 발생.
UBMS는 libevent(BSD) 하나로 Qt의 시그널/슬롯과 이벤트 루프를 대체함으로써
이 라이선스 부담을 원천적으로 회피했다.
9개 외부 의존성 전부가 허용적 라이선스라는 것은 우연이 아니라 의도적 설계.
이는 프로젝트의 법적 자유도를 최대화하며, 투자자나 파트너에게
라이선스 실사(due diligence) 부담이 없는 깨끗한 코드베이스를 제시할 수 있음을 의미.
12.2 범용 라이브러리로의 성장 가능성
UBMS 프로젝트는 블록체인 노드를 만드는 과정에서 부산물로
독립적 가치를 가진 범용 라이브러리를 여럿 생산했다.
이 라이브러리들은 블록체인과 무관한 일반 서버 애플리케이션에도 그대로 사용할 수 있으며,
ubmsnotify(독립 실행 FCM 푸시 알림 서버)가 이를 실증.
독립 배포 가능한 라이브러리:
libubmsio_uring.so io_uring 기반 고성능 네트워크 서버/클라이언트 프레임워크
Server, Client, WebSocket, WebSocketClient, SafeCurl 포함
채팅 서버, IoT 게이트웨이, 게임 서버 등에 즉시 적용 가능
libubmsevent.so libevent 기반 이벤트 엔진 + 비동기 신호-슬롯 + OS 시그널 통합
Qt/Boost 없이 이벤트 구동 애플리케이션 구축 가능
libubmstype.so 독자 직렬화 엔진 (describe() 하나로 JSON + 바이너리 자동 생성)
protobuf/flatbuffers 대체, 외부 코드 생성 도구 불필요
libubmshttp.so REST API + 리버스 프록시 + 리다이렉트 + 레이트 리미팅
nginx 없이 애플리케이션 레벨에서 HTTP 서비스 구축 가능
libubmscrypto.so RSA-4096, SHA-256, RIPEMD-160, Base58, HMAC, zlib 통합
OpenSSL EVP API 래퍼로 암호화 기능 간편 사용
이 라이브러리들의 라이선스 의존성이 전부 허용적(permissive)이므로,
Ubuntu/Debian 패키지(apt)로 배포하거나, vcpkg/Conan 같은 C++ 패키지 매니저에
등록하는 데 법적 장벽이 전혀 없다.
전망:
- C++ 서버 개발 생태계 기여 — io_uring + libevent 조합의 프로덕션급 프레임워크는 오픈소스 시장에서 희소
- 프로젝트 브랜드 확장 — 블록체인 프로젝트가 범용 인프라 도구를 배포하면, 개발자 커뮤니티 신뢰와 프로젝트 인지도가 동시에 상승
- 기술 수익화 경로 — 라이브러리 자체의 상용 지원/컨설팅, 또는 라이브러리를 매개로 한 기술 파트너십 가능
- 인재 유입 — 범용 오픈소스 라이브러리는 외부 기여자를 유인하는 가장 효과적인 수단이며, 이는 블록체인 본체의 품질 향상으로 순환
13. 블록 검증 흐름
UBMS::Chain::addBlock(target)
|
+--> UBMS::Chain::m_mutex.lock()
|
+--> UBMS::InspectManager::validateBlock()
| +--> 해시 검증
| +--> 이전 해시 검증
| +--> 머클루트 검증
| +--> 난이도 검증
| +--> 타임스탬프 검증
|
+--> UBMS::InspectManager::validateBlockTxSignatures()
| +--> 각 TX 서명 검증
|
+--> UBMS::InspectManager::validateBlockInputsNotSpent()
| +--> 입력 UTXO 소비 여부 검사
|
+--> UBMS::CacheManager::addBlock()
| +--> makeDelta() (UTXO 변경분 추출)
| +--> volatile.pushBack(delta)
| +--> confirmed.updateNodeInfo()
| +--> confirmed.addReferral()
| +--> 오버플로우 시 DB 커밋
|
+--> BlockMetaFullCache 업데이트
+--> BlockCurrent 교체
+--> BlockPool에서 제거
|
+--> Chain::m_mutex.unlock()
14. 결론
UBMS(UTXO-Based Metadata Smart Chain)는 100% 독자 개발된 블록체인 풀노드 시스템으로,
"끊임없는 발전: 정지되지 않는 블록체인"을 지향.
수백 개의 헤더/구현 파일, 11개 라이브러리 모듈 + 데몬 + 독립 알림 서버로 구성되며,
외부 프레임워크(Qt, Boost) 없이 표준 C++과 최소한의 허용적 라이선스 라이브러리만으로 전체를 구축했다.
이하는 본 보고서에서 분석한 전체 기술 영역의 요약.
합의 설계 (3항, 5항)
- PoW + PoS + PoB 삼중 합의로 보안성과 공정성을 동시에 달성
- 비콘 체인 없는 완전 분산형 합의 (최소 9노드)
- Shifted Sigmoid 알고리즘으로 대형 스테이커 독식 방지: \(R(x) = \frac{1}{1+e^{-z}}\)
- 2단계 반감기 스케줄 (초반 540블록 급감소 + 후반 210,240블록 4년 주기), 총발행량 약 21,012,500 UBMS
- InspectManager 기반 블록 검증 파이프라인: 해시, 이전 해시, 머클루트, 난이도, 타임스탬프, TX 서명, UTXO 소비 여부를 순차 검증 (13항)
경제 설계 (3항)
- 채굴자 5% + 스테이커 95% 온체인 자동 분배
- PoB 5단계 유통인 수수료 분배 (60/20/10/7/3%)로 네트워크 성장 인센티브
- 동적 수수료: \(F = 1{,}000 \times \sqrt{v/10{,}000} \times CF\)
- 소각 메커니즘: \(\text{PoS 분배율} = \max(0.01,\;\min(1,\;N/10{,}000))\)으로 공급 자동 조절
- UTXO 기반 메타데이터 스마트 컨트랙트 (VM 없이 네이티브 C++ 실행, TTL/조건부 실행 지원)
네트워크 설계 — PSAN (4항, 6.5항)
- 역할 다형성 자율 조정 네트워크(PSAN)로 메시지 플러딩 방지
- 결정론적 2D 격자 + 아핀 편향 3경로 라우팅으로 전통 가십 대비 1/1000 대역 절감 (특허 기술)
- 지향성 가십: 경로 전파 336 vs 전통 가십 399,000 (N=10,000)
- \(\log_2(N)\) 기반 BP 자동 산출: \(R = \max(3,\;\lfloor\log_2(N)/2\rfloor \times 2+1)\), \(V = \max(5,\;\lfloor\log_2(N)/1.2\rfloor \times 2+1)\)
- 독자 DHT(아웃바운드 전용, SHA-256 XOR 거리): Kademlia와 이름만 같을 뿐 근본적으로 다른 독자 설계
- 토폴로지 3초마다 재계산으로 네트워크 적응성
캐시 및 데이터 설계 (3항, 10항, 11항)
- 3계층 캐시(VolatileCache + ConfirmedCache + DB) + TX풀을 단일 잠금로 통합하여 원자적 상태 검사 보장
- 블록차분으로 변경분만 격리하여 롤백이 O(1) (차분 popBack 한 번)
- 확정 데이터 커밋은 10블록마다 일괄 처리로 DB 쓰기 증폭 최소화
- owner/miner/txaddr 3종 인덱스로 주소별 조회 최적화
- txid 타임스탬프 prefix로 별도 시간 인덱스 없이 최신순 조회 가능
- UTXO 모델로 잔액 계산이 명확하고 검증이 용이
기반 라이브러리 (6항)
- io_uring (libubmsio_uring.so) — Multishot Accept/Recv, Zero-Copy Send, Provided Buffer Ring, Fixed FD, Batch Submit, Backpressure 제어. 세대 번호(gen)로 stale CQE 안전 무시
- 이벤트 아키텍처 (libubmsevent.so) — libevent 하나로 Qt 시그널/슬롯, Boost.Asio 이벤트 루프, Boost.Signals2 옵저버 패턴을 전면 대체. event_new + timeval{0,0} 즉시 비동기 디스패치, COW 슬롯 스냅샷, 3-상태 CAS(Alive/Marked/Cleaning) 수명 관리
- HTTP 서버 (libubmshttp.so) — Router(메서드+URI 라우팅) + Forwarder(리버스 프록시, ROUNDROBIN) + Redirector(301/307/308) + Abuse(LRU 레이트 리미팅). nginx 없이 애플리케이션 레벨 HTTP 서비스 구축
- 직렬화 엔진 (libubmstype.so) — describe() 하나로 JSON + 리틀엔디안 바이너리 이중 포맷 자동 생성. 벡터 크기 상한, 버퍼 경계 검사, enum fallback 등 안전 역직렬화 설계
- 암호화 (libubmscrypto.so) — RSA-4096, SHA-256, RIPEMD-160(독립 구현), Base58Check, AES-GCM, HMAC-SHA256, zlib(Zip Bomb 방어 64MB)
멀티스레드 안전성 (7항)
- 9개 컴포넌트별 잠금 전략 체계화: 공유 잠금, 원자적 공유 포인터 + COW, 배타적 잠금 직렬화
- TOCTOU 회피: checkDoubleSpendWithPool 등 원자적 검사 함수 6종으로 이중지불을 구조적으로 차단
- TX풀 4단 충돌 검사: TX 내부 중복, 주소별 예약 풀, 전역 크로스-주소(전역 소비키), 출력 인덱스 중복
- 원자적 공유 포인터로 잠금 없는 읽기 (현재 블록, 블록 메타 전체캐시, 블록풀)
- 잠금 계층 설계: 체인 배타적 잠금 이후 캐시매니저 공유 잠금 이후 내부 잠금 순서로만 취득, 역순 불가 (교착 원천 차단)
성능 (8항)
- io_uring 실측 벤치마크: multishot, zero-copy, provided buffers로 I/O 극대화
- 조회: 최신 TX는 메모리에서 즉시, referral O(1) 해시맵, UTXO 소비 확인 O(10) 최대
- 네트워크: zlib 압축, 메시지 ID 중복 제거, 공개키 LRU 캐싱, sendmsg 배치 전송
보안 설계 (9항)
- 빌드 레벨: FORTIFY_SOURCE, Stack Canary, Stack Clash Protection, CFI, Full RELRO, ASLR(fPIC), noexecstack
- 암호화: RSA-4096, SHA-256 이중 해싱, HMAC-SHA256, Base58Check, Zip Bomb 방어
- 런타임: Arith 오버플로 검사, 서명 중복 검사(윈도우 기반), TOCTOU 원자적 해소, 전역 소비키 크로스-주소 차단
라이선스 독립성 및 범용성 (12항)
- 9개 외부 의존성 전부 허용적 라이선스(Apache 2.0, BSD 3-Clause, MIT, zlib): 소스 공개 의무 없이 상용 배포, 독점 라이선스 전환, 기술 라이선싱 자유
- Qt(LGPL/GPL/상용)와 Boost를 의존성에서 완전 제거하여 라이선스 부담 원천 회피
- libubmsio_uring.so, libubmsevent.so, libubmstype.so, libubmshttp.so, libubmscrypto.so가 블록체인과 무관한 독립 라이브러리로 배포 가능
- ubmsnotify(독립 실행 FCM 푸시 알림 서버)가 라이브러리 범용성을 실증
- Ubuntu/Debian apt 패키지, vcpkg/Conan 등록에 법적 장벽 없다
UBMS는 블록체인 노드를 만드는 과정에서 합의, 네트워크, 캐시, I/O, 이벤트, 직렬화, 보안의
모든 계층을 외부 프레임워크 없이 독자 설계했으며,
그 과정에서 생산된 라이브러리들은 블록체인을 넘어 범용 서버 인프라로서의 가치를 갖는다.
15. 개발 연대표
15.1 구상기 (2022 ~ 2024.10)
- 2022년 — UBMS 구상 시작. UTXO 기반 메타데이터 스마트 체인 콘셉트 확립, 설계 문서 작성, 합의 모델 및 경제 구조 설계, 개발 환경 조성
- 2024.11 — 본격 개발 착수. C++ 표준 라이브러리 + 최소 외부 의존성 원칙 수립
15.2 프로토타입기 (2025.2 ~ 2025.4)
- 2025.2 — PSAN(역할 다형성 자율 조정 네트워크) 구상 공개. 결정론적 2D 격자 위에 역할 기반 라우팅을 결합한 독자 토폴로지 설계. PoB(Proof of Behavior) 5단계 유통인 분배 메커니즘 확정. 오픈베타 일정 예고
- 2025.3 — PSAN 실제 작동 증명. 노드 간 격자 좌표 할당, 아핀 편향 3경로 라우팅, 지향성 가십이 설계대로 동작함을 확인. 국내 주요 거래소(업비트) 상장 코인들의 코드베이스를 조사하여 UBMS 독자성 검증
15.3 공개 테스트기 (2025.5 ~ 2025.7)
- 2025.5 — 로드맵 공개. 백서 초판 완성. 오픈테스트 시작으로 외부 노드 참여 개시
- 2025.6 — Shifted Sigmoid 보상 알고리즘 발견 및 적용.
개발자의 RNN/GRU 기반 AI 개발 경험에서 시그모이드 함수의 특성을 보상 곡선에 응용한 것으로,
기존 블록체인에서 사용하지 않던 독창적 접근.
\(R(x) = \frac{1}{1+e^{-z}}\), \(z = ((x + T \times 0.2)/T - 0.5) \times 10\).
공개 베타테스트 반응이 예상보다 좋아 iOS 지갑 앱 외주 개발 결정.
TLS 적용, P2P 프로토콜 안정화 패치
- 2025.7 — PSAN 셔플 편향성 개선. 기존 SHA-256 + XOR 방식에서 HMAC-SHA256 + XOR 방식으로 전환하여 노드 분배 편향을 ±8%에서 ±1~2%로 개선
15.4 가운영기 (2025.8 ~ 현재)
- 2025.8 — 가운영 준비 완료. ubmsdaemon(풀노드), ubmsmine(채굴기), ubmsmine_and(안드로이드 지갑), ubmscli(CLI), ubmsnotify(알림 서버) 등 5개 프로그램 완성. 로드밸런서 시연으로 다중 노드 운영 체계 검증
- 2025.9 — 가운영 시작. 라이트노드 완성으로 모바일 참여 확대.
Shifted Sigmoid 기울기 계수를 10에서 7로 보정하여 소규모 스테이커 보상 곡선 최적화.
가운영 3일차에 노드당 스테이크 1개 제한 정책 도입 — 다중 스테이크로 보상을 독점하는 시나리오를 실운영에서 발견하고 즉시 대응한 사례
- 2025.10 — 결정론적 2D 격자 라우팅 기술 특허 출원
- 2025.12 — 대규모 아키텍처 업데이트. 토폴로지 전면 재설계, 지향성 가십 최적화, 3계층 캐싱 구조 고도화. 이 시점에서 현재의 캐시 + 블록차분 + 롤백 아키텍처가 확립
- 2026.1 — 서버 인프라 업데이트. 롤백 메커니즘 설계 검증 및 보완
- 2026.2 — 백서 v1.9 발행. 소각 기준을 스테이커 수에서 노드 수로 변경하여 네트워크 참여 기반 경제 모델로 전환.
3D 격자 확장 구상 공개 — 기존 2D 격자(8이웃)를 3D(26이웃)로 확장하여 SNN(Spiking Neural Network) 기반 AI 모델과 결합하는 연구 방향 제시
- 2026.3 — iOS 지갑 앱 출시. 안드로이드/iOS 양대 플랫폼 지갑 완성
15.5 현재 네트워크 현황
- 활성 노드: 148개
- 블록 높이: #29,431
- 채굴량: 9.67%
- 소각량: 5.11%
- 유통량: 4.56% (채굴량 9.67% - 소각량 5.11%)
UBMS Technical Analysis Report
UTXO-Based Metadata Smart Chain
Authors: bokkamsun@gmail.com and 2 others
Date: March 1, 2026
About This Report
UBMS is a project whose development began in November 2024 and continues actively to this day.
It is a living project — one that accumulates real-world data in a pre-production environment,
refining its design and improving its code based on that feedback.
Operations proceed in stages:
Beta Test Ended June 2025, expanded external participation
Pre-production (now) Real data collection in pre-production, accumulating failure experience
Production Transition after codebase completion reflecting pre-production feedback
During the pre-production phase, a forum is maintained for direct communication with participants.
Various failure scenarios are intentionally experienced and response code is written accordingly to ensure stability.
Improvements discovered during pre-production are collected immediately, and the empirical data accumulated through this process
serves as design validation evidence for the economic models (Shifted Sigmoid, PoB, dynamic fees).
A great deal of feedback has been received and is continuously reflected in the codebase.
The code analyzed in this report is based on the v5 branch, representing the skeletal completion stage covering approximately 40% of the overall design.
The technical analysis covers only those portions where the core architecture and major module operations have been verified;
features still under implementation or in internal testing are not included in the scope of this report.
In other words, what this report contains is the technical capability of the completed portions,
and as a long-term project, it will continue to grow in scale well beyond the scope of this report's analysis.
A technical report for a finished product merely explains its deliverables,
but a report at the 40% mark reveals where this project is heading —
what design philosophy and technical aspirations it stands upon.
The skeleton of the code is the designer's intent, and the contours of the completed form are clearly discernible.
Currently a solo development effort, the project plans to expand its team as it grows,
reinforcing external code review, security audits, and automated testing frameworks.
1. Program Overview
UBMS (UTXO-Based Metadata Smart Chain) is a 100% independently developed Korean blockchain full-node system.
Written in C++20, it implements metadata-based smart contracts on top of the UTXO model.
Key features:
- PoW + PoS + PoB hybrid consensus algorithm
- PSAN (Polymorphic Self-Adjusting Network) architecture
- Shifted Sigmoid algorithm-based staking reward distribution
- Deterministic 2D grid-based multi-path routing (patented technology)
- High-performance asynchronous I/O based on Linux io_uring
- 3-tier cache architecture for maximum query performance
- Fully decentralized consensus without a beacon chain
Total supply: ~21,000,000 UBMS, 8 decimal places (mensch unit = 100,000,000)
Block reward distribution: Miner 5% + Staker 95% on-chain automatic distribution
2. Module Structure
ubmscoin/
src/
libubmstype.so Type definitions, JSON/binary serialization engine
libubmslog.so File-based logging
libubmsutil.so Worker template, thread-safe queue, arithmetic overflow protection, conversion utilities
libubmscrypto.so RSA-4096, SHA256, RIPEMD160, Base58, AES-GCM, zlib compression
libubmsio_uring.so io_uring-based server/client, WebSocket, session management
libubmsevent.so libevent-based event engine, signal-slot, OS signal integration
libubmstopol.so Deterministic 2D grid, 3-path routing, directional gossip, proprietary DHT
libubmshttp.so REST API + reverse proxy + redirect + rate limiting
libubmscoin.so Blockchain core (block, TX, UTXO, cache, DB, validation)
ubmsdaemon Daemon entry point, P2P hub, worker threads
ubmsnotify Standalone FCM push notification server (library versatility demonstration)
Dependency graph:
libubmstype.so (base)
libubmslog.so
libubmsutil.so (Worker, QueueSafe, Arith, Convert)
libubmscrypto.so (RSA, SHA256, Base58, zlib)
libubmsio_uring.so (io_uring-based server/client)
libubmsevent.so (event loop, signal-slot)
libubmstopol.so (proprietary DHT, topology)
libubmshttp.so (REST API)
libubmscoin.so (blockchain core)
ubmsdaemon (daemon + P2P)
ubmsnotify (standalone push notification server, library versatility demonstration)
3. Core Architecture
3.1 3-Tier Cache + TX Pool Unified Architecture
CacheManager is the central control tower that governs the 3-tier cache and TX pool under a single lock.
It absorbs UTXO lookups, balance calculations, and double-spend checks to guarantee atomic state inspection.
UBMS::CacheManager (Internal lookups are O(10) or less, so lock hold time is extremely short)
│
├── UBMS::TxCurrent (TX pool + per-address reservation pool)
│ m_tx: timestamp-ordered TX map
│ m_reserved: per-address UBMS::UtxoPool
│ ├─ spent_keys: UTXO keys reserved for spending
│ ├─ spent_list: spent input list
│ └─ available: TX pool change (unspent UTXO)
│ m_globalSpentKeys: cross-address double-spend defense
│
├── [Tier 1] UBMS::VolatileCache (last 10 blocks)
│ std::list<UBMS::BlockDelta> m_deltas
│ UBMS::BlockDelta = {
│ m_addedUtxo: newly created UTXO (map)
│ m_spentKeys: spent UTXO keys (set)
│ m_spentUtxoInfo: owner/miner of spent UTXO
│ m_transactions: TX list (signatures stripped)
│ m_addedReferrals: new referral relations
│ m_mineAddress, m_reward
│ }
│ Rollback = single popBack and done
│ Lookup = reverse scan from latest (O(10) max)
│
├── [Tier 2] UBMS::ConfirmedCache (memory-resident)
│ m_childToParent: referral 1:1 map
│ m_parentToChildren: referral 1:N map
│ m_nodeInfo: per-miner statistics
│ m_mineTimeLast: mining times of last 100 blocks
│
└── [Tier 3] DB (persistent storage)
Stores TX, UTXO, owner/miner/address indices
Bloom filter for fast non-existent key exclusion
Query Priority (fallback from upper cache)
UTXO spend check (isSpentKey):
1) volatile.spentKeys → if true, already spent
2) volatile.addedUtxo → if found, unspent
3) DB lookup → if not found, spent
Balance query (getBalance):
DB(owner index) + volatile(addedUtxo - spentKeys) combined
TX pool integrated query (getInputWithPool):
DB UTXO + volatile filtering + TX pool change(available) merged
BlockDelta Change Extraction (makeDelta)
The process by which a single block is converted into a single delta:
makeDelta(block):
Step 1: Copy block basic info (height, hash, mineAddress, reward)
Step 2: Process each TX
a) strip signature, publicKey → m_transactions (memory saving)
b) output → convert to UBMS::S_UTXO → m_addedUtxo[txid:index]
c) input → m_spentKeys.insert(txid:index)
d) referral → m_addedReferrals.push_back({child, parent})
Step 3: staking rewards → add to m_addedUtxo
Step 4: deduplication (if added and deleted in same TX, deletion takes priority)
for each spentKey: m_addedUtxo.erase(key)
Step 5: spent UTXO info pre-collection
for each spentKey:
pre-query owner/minerAddress from volatile or DB
→ m_spentUtxoInfo[key] = {owner, minerAddress}
→ enables safe index deletion even if getUTXO fails during DB commit
Elegant Rollback Strategy
Add (addBlock):
makeDelta(block)
→ m_confirmed.applyDelta(delta) // immediately apply referral/node info
→ m_volatile.pushBack(delta) // add to delta list
→ if size > 10: popFront → commitToDb() // migrate oldest to DB
Rollback (rollBack):
m_volatile.popBack() // remove entire delta (O(1))
m_confirmed.rollbackReferrals() // remove referrals in reverse
m_confirmed.rollbackNodeInfo() // decrement mining statistics
→ no index cleanup needed, no UTXO add/subtract needed
→ automatic restoration by simply removing delta
Compared to Bitcoin Core's DisconnectBlock:
Bitcoin: reverse-recalculate each TX's input/output → O(TX count)
UBMS: pop entire delta → O(1)
DB Commit + Index Generation (commitToDb)
When volatile exceeds 10 blocks, the oldest delta is batch-committed.
commitToDb(delta):
WriteBatch _batch; // atomic batch write
1) TX storage + per-address index
for each tx:
addTx(tx)
addTxAddrIndex(tx.address, txid) // sender index
for each output:
addTxAddrIndex(output.to, txid) // receiver index
2) UTXO add + owner/miner index
for each addedUtxo:
addUTXO(utxo)
addOwnerIndex(owner, key)
if stake.LOCK:
addMinerIndex(minerAddr, key)
3) UTXO delete (spent) + index removal
for each spentKey:
if pre-collected info exists in m_spentUtxoInfo: ← key point
safely delete owner/miner index (no DB re-query needed)
else:
query via getUTXO from DB (fallback)
removeUTXO(txid, index)
4) Referral storage
5) CommittedHeight update
6) execBatch(_batch) // all succeed or all fail
Why spent UTXO pre-collection is critical:
- When a delta is migrated to DB 10 blocks later, the original UTXO has already been removed from volatile
- A getUTXO query from DB may fail (another delta may have been committed first)
- Pre-collected owner/minerAddress enables safe index deletion — preventing orphaned indexes
Three Index Types in Detail
| Index | Created | Deleted | Purpose |
| owner | On UTXO creation | On UTXO spend | Per-address balance/UTXO lookup |
| miner | On stake LOCK | On UTXO spend | Delegated stake per miner |
| txaddr | On TX commit | Never (historical) | Per-address TX history lookup |
getBalance(address):
DB owner index prefix scan
+ matching owner in volatile addedUtxo
- excluding volatile spentKeys
= final balance
getStakeToMine(minerAddress):
DB miner index prefix scan
+ volatile stake.LOCK && matching minerAddress
= list of stakes delegated to the miner
getTx(address):
DB address index prefix scan
+ matching address in volatile m_transactions
= full TX history for the address
Operational flow:
block add -> makeDelta(extract changes) -> pushBack to volatile
-> if exceeds 10 -> commit oldest delta to DB (batch write)
-> TX pool cleanup -> index generation
3.2 Independently Designed UTXO Model
The UBMS UTXO shares only the name "UTXO" with Bitcoin; its internal structure is entirely original.
It does not use Bitcoin's Script-based lock/unlock model, and is built on a proprietary type system.
Bitcoin UTXO vs UBMS UTXO Structure Comparison
Bitcoin UTXO (CTxOut)
nValue amount (satoshi)
scriptPubKey locking script (Script bytecode)
→ Script interpreter evaluates lock/unlock
→ fixed binary serialization (CSerialize)
→ no staking concept
→ no metadata
UBMS UTXO (UBMS::S_UTXO : UBMS::Serializable)
index output index
amount amount (mensch unit)
timestamp creation timestamp
owner owner address
txid original transaction ID
stake { staking state machine (UBMS::S_STAKE)
state NONE → LOCK → UNLOCK state transition
minerAddress delegated miner address
}
ubms { metadata contract (UBMS::S_UBMS)
metaData JSON on-chain metadata
ttl TTL (auto-expire on expiration)
conditions conditional execution rules
}
Proprietary Type System (UBMS::Serializable)
Every data structure in UBMS inherits from the independently developed Serializable framework.
This is an entirely different design from Bitcoin's CSerialize macros or Ethereum's RLP encoding.
UBMS::Serializable (base class)
├─ describe() pure virtual function for self-descriptive field registration
├─ reg() primitive types (uint64_t, string, bool, float, double)
├─ regEnum() enum with range validation
├─ regStruct() nested struct (recursive serialization)
├─ regVec() struct vector (OOM defense: size cap)
├─ regSet() string set
├─ regRawTail() entire remaining buffer as raw binary
├─ regPtrStatus() shared_ptr presence as bool only
│
├─ toJson() / fromJson() automatic JSON conversion
├─ serialize() / deserialize() automatic binary conversion
└─ E_REG_FLAG: REG_ALL / REG_JSON_ONLY / REG_BIN_ONLY per-format field selection
Core design principles:
1. Self-descriptive: registering fields in describe() auto-generates bidirectional JSON/binary serialization
2. Dual format: a single struct supports both JSON for REST API and binary for P2P simultaneously
3. Recursive composition: unlimited nesting of complex structures via regStruct/regVec
4. Safe deserialization: buffer boundary check, vector size cap, enum range validation, type mismatch ignored
5. Format separation: REG_JSON_ONLY/REG_BIN_ONLY expose different fields for network transmission vs API response
UBMS Type Hierarchy
UBMS::Serializable (libubmstype.so)
│
├── UBMS::S_UBMS metadata (metaData, ttl, conditions)
├── UBMS::S_STAKE staking state (state, minerAddress)
├── UBMS::S_INPUT TX input (txid, index, amount, stake, ubms)
├── UBMS::S_OUTPUT TX output (to, amount, index, stake, ubms)
├── UBMS::S_REFERRAL referral relation (child, parent, ref[])
├── UBMS::S_REFERRAL_TREE referral tree (recursive structure: name, level, children[])
├── UBMS::S_REWARD reward info (owner, amount, reward, txid)
├── UBMS::S_TRANSACTION transaction (type, in[], out[], referral, signature)
├── UBMS::S_BLOCK block (header + transaction[] + stakeReward[])
├── UBMS::S_BLOCK_META block storage location (fileName, fileOffset, dataSize)
├── UBMS::S_BLOCK_MINI lightweight block (minimum fields for validators only)
├── UBMS::S_HEIGHT peer height info
├── UBMS::S_MINE_INFO mining info (stakers[], transactions[], height)
├── UBMS::S_WALLET wallet (address, balance, publicKey)
├── UBMS::S_MESSAGE P2P message (header, path[], avoid{}, payload)
│ setPayload<T>() / getPayload<T>() generic payload
│
├── UBMS::S_INPUT_LIST input list container (independent serialization)
├── UBMS::S_BLOCK_LIST block list container (independent serialization)
└── UBMS::S_TRANSACTION_LIST transaction list container (independent serialization)
Key Differences from Bitcoin — Summary
| Aspect | Bitcoin UTXO | UBMS UTXO |
| Lock model | Script bytecode (OP_DUP, OP_HASH160...) | State machine (NONE→LOCK→UNLOCK) |
| Script VM | Script interpreter required | No VM — native C++ processing |
| Staking | Not possible (external protocol needed) | S_STAKE built into the UTXO itself |
| Metadata | OP_RETURN limited to 80 bytes | S_UBMS: JSON meta + TTL + conditions, unlimited |
| Serialization | CSerialize macros (binary only) | Serializable: automatic dual JSON + binary generation |
| Referral | Not possible | S_REFERRAL: 5-level distributor chain built-in |
| Rewards | Single coinbase TX | S_REWARD[]: mining 5% + staking 95% distribution |
| Verification propagation | Full block transmission | S_BLOCK_MINI: lightweight block for validator bandwidth savings |
| Delegated mining | Not possible | UTXO-level delegation via S_STAKE.minerAddress |
UBMS borrows only the conceptual model of UTXO (tracking unspent outputs);
the lock/unlock mechanism, state management, metadata, and serialization engine are all entirely original designs.
UTXO query order:
DB(owner index) -> filter spent in volatile -> reflect TX pool reservation pool
= final available balance
3.3 Shifted Sigmoid Reward Algorithm
The Shifted Sigmoid, a core algorithm of UBMS, distributes staking rewards in a nonlinear fashion.
Its purpose is to structurally prevent large stakeholders from monopolizing rewards.
Sigmoid Weight Calculation (Whitepaper Formula)
$$R(x) = \frac{1}{1 + e^{-z}}$$
$$z = \left(\frac{x + s}{T} - 0.5\right) \times 10$$
x : staker's stake amount
T : total stake sum of all stakers
r = 0.2 (left shift ratio)
s = T × r (shift value)
multiply by 10 to meaningfully amplify the gap between small and large stakeholders
Per-Staker Reward Formula
$$\text{reward}(x) = (\text{block reward} \times 95\%) \times \frac{R(x)}{\sum R(x_i)}$$
$$z = \left(\frac{x + T \times 0.2}{T} - 0.5\right) \times 10$$
Reward distribution structure:
Block reward distribution:
Miner: 5% of block reward ← PoW
Staker: 95% of block reward ← PoS (distributed by Shifted Sigmoid ratio)
Effects:
- Prevention of whale monopolization — Rewards follow a curve rather than a linear function, preventing large holders from disproportionately capturing rewards
- Small-stake participant correction — Even modest stakes earn meaningful rewards, encouraging sustained participation
- Mathematical soundness — The shifted Sigmoid preserves total reward integrity even after normalization
3.3.1 Burn Mechanism
During PoS reward distribution, a built-in supply regulation mechanism automatically burns a portion of rewards when the number of participating nodes is low.
$$\text{PoS distribution rate} = \max(0.01,\;\min(1,\;\tfrac{N}{10{,}000})) \times 100\%$$
$$\text{PoS burn rate} = \Big(1 - \max(0.01,\;\min(1,\;\tfrac{N}{10{,}000}))\Big) \times 100\%$$
Node count Dist. rate Burn rate Note
0 0% 100% entire PoS reward burned
100 1% 99% 1% distributed, 99% burned
1,000 10% 90% 10% distributed, 90% burned
5,000 50% 50% 50% distributed, 50% burned
9,500 95% 5% 95% distributed, 5% burned
10,000 or more 100% 0% fully distributed, no burn
Design effects:
- Automatic supply restriction when node count is low, preventing inflation
- Incentivizes node participation — distribution scales proportionally with participant count
- Long-term ecosystem balance — maintains network health
3.4 Halving Schedule
Early Mining Phase
Mining period: 6 hours = 6 × 60 × 60 = 21,600 seconds
Block generation time: 10 seconds/block
Total blocks: 21,600 / 10 = 2,160 blocks
Halving interval: 540 blocks
Initial reward R₀: 1,000 UBMS/block
Halving count: 4 times
Mining output per interval:
Interval 1: R₀ = 1,000 × 540 = 540,000 UBMS (block 0 ~ 539)
Interval 2: R₀/2 = 500 × 540 = 270,000 UBMS (block 540 ~ 1,079)
Interval 3: R₀/4 = 250 × 540 = 135,000 UBMS (block 1,080 ~ 1,619)
Interval 4: R₀/8 = 125 × 540 = 67,500 UBMS (block 1,620 ~ 2,159)
─────────────────────────────────────────────
$$C_1 = \sum C_{1i} = 1{,}012{,}500 \;\text{UBMS}$$
Late Mining Phase
Block generation time: 10 min/block
Annual blocks: 365 × 24 × 60 / 10 = 52,560 blocks/year
Halving interval: 4 × 52,560 = 210,240 blocks (approx. 4 years)
Late phase initial reward R₀': 48 UBMS/block
Mining output per interval:
Interval 5: 48 × 210,240 = 10,091,520 UBMS (block 2,160 ~ 212,399)
Interval 6: 24 × 210,240 = 5,045,760 UBMS (block 212,400 ~ 422,639)
Interval 7: 12 × 210,240 = 2,522,880 UBMS (block 422,640 ~ 632,879)
Interval 8: 6 × 210,240 = 1,261,440 UBMS (block 632,880 ~ 843,119)
Interval 9: 3 × 210,240 = 630,720 UBMS (block 843,120 ~ 1,053,359)
Interval 10: 1.5 × 210,240 = 315,360 UBMS (block 1,053,360 ~ 1,263,599)
Interval 11: 0.75 × 210,240 = 157,680 UBMS (block 1,263,600 ~ 1,473,839)
─────────────────────────────────────────────
$$C_2 = \sum C_{2j} \approx 20{,}000{,}000 \;\text{UBMS}$$
Total Supply Summary
$$\text{total supply} = C_1 + C_2 = 1{,}012{,}500 + 20{,}000{,}000 \approx 21{,}012{,}500 \;\text{UBMS}$$
actual circulation is less after PoS burn deduction
3.5 PoB (Proof of Behavior) — 5-Tier Distributor Fee Allocation
PoB, the third consensus pillar of UBMS, is a "proof of behavior" mechanism.
Transaction fees are automatically distributed on-chain along a 5-tier distributor chain.
Fee Distribution Ratios (Per Whitepaper)
when total fee = F:
Tier 1 (direct referrer) → F × 60%
Tier 2 → F × 20%
Tier 3 → F × 10%
Tier 4 → F × 7%
Tier 5 (top-level) → F × 3%
───────────────────────────
Total 100%
Effects:
- Continuous incentives for distributors who contribute to network growth
- On-chain mining through transaction fees (fee mining)
- Referral relationships reside in ConfirmedCache in memory, enabling fast lookups
3.6 Dynamic Fee Structure
Fees are not fixed but automatically adjusted according to market conditions. External market price data is used to derive a reasonable fee.
$$EF = \sqrt{\frac{v}{v_0}} = \sqrt{\frac{v}{10{,}000}}$$
$$F = B \times EF \times CF = 1{,}000 \times \sqrt{\frac{v}{10{,}000}} \times CF$$
v₀ = 10,000 KRW (reference market price)
B = 1,000 KRW (base fee)
CF = reflects congestion of last 250 blocks, default 1.0
Calculation examples:
Example 1: market price v = 10,000 KRW
EF = √(10,000 / 10,000) = √1 = 1
F = 1,000 × 1 × 1.0 = 1,000 KRW
Example 2: market price v = 100,000,000 KRW
EF = √(100,000,000 / 10,000) = √10,000 = 100
F = 1,000 × 100 × 1.0 = 100,000 KRW
While Bitcoin and Ethereum use fixed or congestion-based fees regardless of transaction value,
UBMS introduces an external market price-based economic factor to achieve fees proportional to transaction scale.
3.7 UTXO-Based Metadata Smart Contracts
UBMS implements smart contracts by embedding metadata on top of UTXOs.
This is a UTXO extension approach rather than Ethereum's account model.
UBMS::S_UTXO.ubms fields:
meta metadata (on-chain storage)
ttl TTL (auto-expire on expiration)
exec conditional UTXO lock/unlock
Hybrid on-chain/off-chain execution model:
- On-chain: conditional execution, TTL, metadata storage
- Off-chain: complex computations are processed externally, with only the results recorded on-chain
4. PSAN Network Architecture
PSAN (Role-Polymorphic Self-Adjusting Network) is the P2P network design philosophy of UBMS.
Core Principles
1. role polymorphism: single node dynamically performs relay/voter/miner roles
2. self-adjustment: automatically calculates BP count based on network size
3. CF mitigation: prevents message flooding, eliminates bandwidth waste via deterministic paths
BP (Blueprint) Calculation Formula (Per Whitepaper)
$$R = \max\!\Big(3,\;\lfloor \log_2(N) \,/\, 2 \rfloor \times 2 + 1\Big)$$
$$V = \max\!\Big(5,\;\lfloor \log_2(N) \,/\, 1.2 \rfloor \times 2 + 1\Big)$$
N = total node count, always odd to ensure clear majority voting
BP Examples by Node Count
100 nodes: log₂(100) ≈ 6.64 → R = 3, V = 11
1,000 nodes: log₂(1000) ≈ 9.96 → R = 5, V = 21
10,000 nodes: log₂(10000) ≈ 13.28 → R = 7, V = 51
100,000 nodes: log₂(100000) ≈ 16.61→ R = 11, V = 101
Minimum Consensus Requirements
relay nodes 3 or more
voting nodes 5 or more
mining nodes 1 or more
Total consensus achievable with minimum 9 nodes
fully decentralized consensus without beacon chain:
without separate beacon chain or central coordinator
consensus achieved through direct inter-node voting
4.1 Threading Model
Main Thread
UBMS::EventBase (signal processing)
P2P Hub
UBMS::UringPool (threads per CPU core count)
UBMS::ServerBinP2P (inbound P2P)
UBMS::ServerWeb (WebSocket)
Worker Threads (each with independent queue)
UBMS::DecodeWorker (binary frame decoding)
UBMS::SendWorker (message serialization + send)
UBMS::NodeWorker (peer management, topology)
UBMS::ChainWorker (block mining, validation, sync)
UBMS::TxWorker (transaction propagation)
4.2 Message Flow
Inbound:
UBMS::ServerBinP2P::onRead (UBMS::UringPool thread)
-> push to DecodeWorker queue
-> 32-byte message ID dedup check
-> plaintext unwrap or decrypt
-> p2p::execPlain/execCrypto (routing)
-> push to NodeWorker / ChainWorker / TxWorker queue
Outbound:
Worker calls UBMS::SendWorker::sendToOutbound()
-> serialize + compress (plaintext) or encrypt
-> 32-byte message ID generation
4.3 P2P Protocol
Message structure (UBMS::S_MESSAGE):
messageId 32-byte hash
header command identifier (REQUEST_INIT, VOTE_BLOCK, ADD_BLOCK, etc.)
type payload type
payload serialized data
ttl gossip propagation TTL (default 5)
priority priority
path routing path
Peer handshake:
outbound connect -> REQUEST_INIT(plaintext) -> RESPONSE_INIT(plaintext)
-> REQUEST_PEER_LIST(encrypted) -> RESPONSE_PEER_LIST(encrypted)
-> topology construction
Three gossip modes:
GOSSIP propagate to 5 random peers (traditional gossip, auxiliary)
TTL=5, XOR modulo-2 based peer distance calculation
GOSSIP_PATH path-embedded forwarding (3 paths: shortest + left-biased + right-biased)
carries path[] in message and advances one node at a time
loop structurally blocked, no intermediate decision needed
GOSSIP_DIR directional gossip (deterministic grid-based fan-shaped propagation)
direction vector u=(sx,sy) embedded in message
select only forward neighbors (delta dot u > 0)
max fanout 3, TTL = max(3, floor(0.8 * diagonal))
4.4 Consensus Flow (PoW + PoS + PoB Hybrid)
RESET (round reset)
-> REQUEST_MINE_INFO (TX list collection)
-> MINE (PoW: block creation, difficulty-satisfying hash search)
-> DISTRIBUTE_BLOCK (deliver to validators via PSAN path)
-> VOTE_BLOCK (PoS: staker validators vote)
-> VOTE_BLOCK_AGREE (70%+ approval, BFT 2/3 threshold + safety margin)
-> ADD_BLOCK (add to chain)
+-> miner reward 5%
+-> staker reward 95% (Shifted Sigmoid distribution)
+-> TX fee -> 5-tier distributor distribution (PoB: 60/20/10/7/3%)
-> new RESET
When blocks are missing:
REQUEST_BLOCK -> RESPONSE_BLOCK -> ACCEPT_RESPONSE_BLOCK
-> switch to normal mode when height catches up
5. Validation System
UBMS::InspectManager integrates and manages nine specialized validators.
UBMS::InspectTx TX structure validation
UBMS::InspectUtxo UTXO validity
UBMS::InspectBlock block hash, prev hash, merkle root, difficulty, timestamp
UBMS::InspectInput input validity
UBMS::InspectSpent UTXO spend status
UBMS::InspectStake stake validation
UBMS::InspectReferral referral validation
UBMS::InspectBalance balance validation
UBMS::InspectSignature signature validation
Signature replay prevention: recent signatures are tracked using a sliding window.
Inspector (audit tool):
execute per-address comprehensive audit via buildReport()
- UTXO snapshot vs DB consistency
- mining reward table validation
- full block replay simulation
- double-spend detection
6. Core Library Features
6.1 io_uring Asynchronous I/O (libubmsio_uring.so)
A high-performance I/O engine that directly wraps Linux io_uring.
It replaces libevent's bufferevent and performs the same work with significantly fewer system calls.
Key optimizations:
Multishot Accept/Recv continuous receive without re-registering SQE
Zero-Copy Send kernel directly references buffer, no memory copy
Provided Buffer Ring kernel-managed buffer pool, no allocation cost
Fixed FD pre-registered fd, no lookup cost
Batch Submit submit multiple SQEs at once
Backpressure memory stability via recv/send queue size limits
Generation numbers (gen) detect stale CQEs: completion events that arrive after a connection has been closed are safely ignored.
UBMS::UringSession manages per-fd state, with reference counting (incRef/decRef) ensuring safe resource cleanup.
6.2 libevent-Based Event Architecture — An Independent Design Without Qt or Boost
UBMS replaced Qt's signal/slot mechanism, Boost.Asio's event loop, and Boost.Signals2's observer pattern
entirely with libevent alone. Without depending on external GUI frameworks or heavyweight libraries,
it built a proprietary event system spanning six domains on top of libevent's event loop.
6.2.1 Event Loop Engine
A wrapper that runs libevent's event_base on a dedicated thread.
The EVLOOP_NO_EXIT_ON_EMPTY flag keeps the loop alive even when no events are pending,
and event_base_loopbreak provides safe shutdown. This is the heartbeat of UBMS's entire event system.
UBMS::EventBase
event_base_new() create event loop
event_base_loop() persistent operation via EVLOOP_NO_EXIT_ON_EMPTY
event_base_loopbreak() safe shutdown
evthread_use_pthreads() enable multi-thread safety
6.2.2 Signal-Slot System — libevent Repurposed as an Asynchronous Dispatcher
Qt's signal/slot reimplemented on top of libevent. The key idea is to create a timer event with event_new
but fire it immediately with timeval{0,0}, causing the event loop to asynchronously dispatch slot callbacks.
Usage example:
// connect: register slot (lifetime-safe via weak_ptr)
signal.connect(instance, "onBlock", &Handler::onNewBlock);
// emit: immediately schedule to libevent queue, event loop executes callback
signal.emit(instance, "onBlock", blockData);
Internal mechanics of emit:
1. Acquire COW slot snapshot (copy shared_ptr ref only, no vector copy)
2. Create EmitEvent struct (args + slot snapshot + instance)
3. Register libevent event via event_new(base, -1, EV_TIMEOUT, cb_emit, emitEvent)
4. Schedule immediate firing via event_add(ev, timeval{0,0})
5. cb_emit iterates slot snapshot and executes callbacks on event loop thread
Safety design — five layers of defense:
weak_ptr capture never callback to destroyed object (prevents UAF)
COW slot vector safe connect/disconnect during emit (lock-free read)
3-phase state machine Alive -> Marked -> Cleaning (CAS transition, prevents re-entry)
m_cbCount atomic counter destructor waits for in-progress callbacks to complete (double UAF prevention)
event_base_once cleanup safely deferred-free marked events on event loop
Qt's signal/slot requires the MOC code generator, and Boost.Signals2 increases compile times due to header bloat.
UBMS's signal-slot achieves type-safe asynchronous signal-slot functionality using pure C++ templates alone,
with no external code generation tools required.
The signal manager maintains a type_index registry for global signals,
enabling loose coupling between modules without direct cross-references.
6.2.3 HTTP Server (libubmshttp.so) — REST API Built on libevent's evhttp
A complete REST API server built on libevent's evhttp.
It runs independently on its own event loop thread and supports runtime rebinding (rebind).
UBMS::Http owns its own UBMS::EventBase, independent thread HTTP server
UBMS::Router method+URI routing table (shared_mutex protected)
addRoute: externally accessible endpoint
addLocal: local-only endpoint (admin API separation)
UBMS::Forwarder reverse proxy, FIXED/ROUNDROBIN policy
preserves path/query, excludes local requests, prefix filtering
UBMS::Redirector 301/302/307/308 redirect, ROUNDROBIN distribution
status code selection considering browser cache (307 temporary vs 308 permanent)
UBMS::Abuse per IP+URI request limiting, memory cap via LRU cache
UBMS::HttpRequest hook for forwarding/redirect pipeline via onPreRoute
Request processing flow:
evhttp request arrives
-> Abuse check (Rate Limiting)
-> onPreRoute (intercept in order: Redirector -> Forwarder)
-> Router.route() (method+URI matching)
-> execute handler -> sendResponse
With this architecture, a single HTTP server provides REST API + reverse proxy + redirect + rate limiting
using just one library (libevent). The node itself performs all of these functions without nginx or a separate proxy server.
6.2.4 OS Signal Handling
POSIX signals (SIGINT, SIGTERM, etc.) are integrated into libevent's event loop.
evsignal_new converts signals into events, allowing async-unsafe operations
to be safely processed on the event loop thread.
UBMS::SignalHandler _sigHandler;
_sigHandler.on(SIGINT, [](int){ g_running.store(false); });
_sigHandler.on(SIGTERM, [](int){ g_running.store(false); });
_sigHandler.start(eventBase.getBase());
6.2.5 Event Loop Pool
N event loops are created to support parallel event processing.
Symmetrical in structure with the io_uring pool — io_uring handles I/O while the event loop pool handles logic events,
forming a dual event engine architecture.
6.2.6 Design Summary — Six Roles from a Single Library (libevent)
| Role | libevent API | Replaces |
| Event loop engine | event_base_loop | Boost.Asio io_context |
| Async signal-slot | event_new + EV_TIMEOUT | Qt signal/slot, Boost.Signals2 |
| HTTP REST server | evhttp | nginx, Express, Flask |
| Reverse proxy | evhttp + libcurl | nginx proxy_pass |
| OS signal integration | evsignal_new | Direct signal() calls |
| Timer/periodic events | event_add + EV_PERSIST | Separate timer libraries |
Without heavyweight dependencies like Qt (~50MB) or Boost (~150MB headers), libevent (~1MB) alone delivers
both a GUI-framework-class event system and web server capabilities.
This directly contributes to faster build times, minimal deployment size, and easier cross-compilation.
6.2.7 ubmsnotify — A Practical Demonstration of Library Versatility
ubmsnotify is an independently running application of the UBMS blockchain.
It operates as a separate process from the main node (ubmsdaemon), receiving block events in real time
and sending FCM push notifications to mobile devices.
The technical significance of this program is that it demonstrates libubmsevent.so and libubmsio_uring.so
are not blockchain-node-specific but function as a general-purpose server application framework.
ubmsnotify architecture:
ubmsnotify (standalone binary)
UBMS::EventBase libevent event loop (libubmsevent.so)
UBMS::SignalHandler SIGINT/SIGTERM safe handling (libubmsevent.so)
UBMS::UringPool io_uring-based network I/O (libubmsio_uring.so)
WebSocket Server receive mobile client connections (libubmsio_uring.so)
WebSocketClient subscribe to external blockchain node (libubmsio_uring.so)
WorkQueue single worker thread + 1-second periodic tick (self-implemented)
FcmSender Google FCM HTTP v1 API (libcurl + OpenSSL)
ConsoleView terminal dashboard (fmt::color + ANSI escape + ioctl terminal detection)
Operational flow:
1. Receive mobile app connections via WebSocket server, register FCM token + wallet address
2. WSS connect to blockchain node via WebSocketClient, subscribe new blocks
3. On block arrival, match registered addresses in TX/stake rewards
4. Send push notification via matched address's FCM token
5. Auto-renew tokens, auto-remove NOT_FOUND tokens, auto-reconnect external connections
Key design characteristics:
Thread safety all I/O callbacks serialized to worker thread via WorkQueue.post()
no mutex for data protection, only mutex for queue operations
Auto-recovery auto-renew on FCM token expiry, auto-reconnect on external node disconnect
Resource mgmt LRU-based token map, auto-remove invalid tokens
What this proves:
libubmsevent.so (UBMS::EventBase + UBMS::SignalHandler) usable independently as event loop framework
libubmsio_uring.so (UBMS::UringPool + WebSocket) usable independently as network server framework
Combining both libraries can build general-purpose real-time server applications
If these libraries were distributed as Ubuntu packages, they could be used as-is for general server applications
unrelated to blockchain (chat servers, IoT gateways, real-time monitoring servers, etc.).
This stands as a case where a blockchain project produced general-purpose infrastructure libraries,
demonstrating not only technical depth but practical industrial value beyond the project itself.
6.3 Cryptography (libubmscrypto.so)
RSA-4096 key generation, signing, verification, encryption
SHA-256 block/TX hashing
RIPEMD-160 address generation (independent implementation, no OpenSSL dependency)
Base58Check Bitcoin-compatible address encoding
AES-GCM session encryption (in progress)
HMAC-SHA256 message authentication
zlib message compression (Zip Bomb defense: 64MB limit)
Uses OpenSSL 3.x EVP API with both default and legacy providers loaded.
Future plans: add elliptic curve cryptography (ECDSA/Ed25519) to improve signature size and key generation speed,
and leverage OpenSSL 3.x's provider architecture for post-quantum cryptography (PQC) algorithm integration.
6.4 Proprietary Serialization Engine (libubmstype.so)
libubmstype.so is a proprietary serialization framework that serves as the foundation for all data structures in UBMS.
// Actual UBMS::S_UTXO describe() — this alone auto-generates JSON + binary serialization
void UBMS::S_UTXO::describe() {
reg("index", index);
reg("amount", amount);
reg("timestamp", timestamp);
reg("owner", owner);
reg("txid", txid);
regStruct("stake", stake); // S_STAKE recursive serialization
regStruct("ubms", ubms); // S_UBMS recursive serialization
Serial layer (little-endian binary codec):
UBMS::Serial::writeUInt64/readUInt64 8-byte little-endian
UBMS::Serial::writeString/readString length-prefixed string
UBMS::Serial::writeVector/readVector template-specialized vector
→ vector size cap defends against OOM attacks
→ remaining buffer size check prevents buffer overread
Safe deserialization design:
- skip remaining fields on buffer boundary overflow (safe partial object creation)
- restore to fallback value if enum value out of range
- ignore field on JSON type mismatch (crash prevention)
- vector size cap + remaining buffer size check
6.5 Topology (libubmstopol.so) — Deterministic 2D Grid + Directional Gossip
This module is a patent-pending proprietary technology.
Core idea: place all peers on the same checkerboard using the same seed, then compute routes on top of it.
6.5.1 Deterministic Grid Placement
1. compute HMAC-SHA256 hash from each peer's IP and seed
2. quarter the hash, XOR-fold to generate threshold
3. sort ascending by (threshold, IP) pair
4. place sequentially in S x S grid by sort order (S = ceil(sqrt(N)))
5. coordinates: r = i / S, c = i % S
$$h_p = \text{LOW}_w\!\big(\,F(\text{seed}) \oplus F(\text{ip}(p))\,\big)$$
sort key = (h_p, ip) ascending
6.5.2 Shortest Path Algorithm — Straight-First BFS
Finding the shortest path between a start node and a goal node on the 2D grid
is the core of the path-based propagation method (GOSSIP_PATH).
UBMS uses Straight-First BFS, an extension of standard BFS tailored to grid characteristics.
Graph modeling:
each cell on the S × S grid is a node, 8-directional neighbors are edges (all weight 1).
4 cardinal + 4 diagonal = max 8 neighbors.
border cells have fewer neighbors, empty cells (no peer placed) are skipped.
Algorithm details (shorPathIndex):
Input: start index s, target index g
Output: s -> g shortest path (node index array)
output: s -> g shortest path (node index array)
1. Initialization
dist[N] = -1 (unvisited), prev[N] = -1 (no parent)
pdx[N], pdy[N] = 0 (for recording entry direction when reaching each node)
dist[s] = 0, insert s into queue
2. BFS Loop
dequeue u
if u == g, terminate immediately
get 8-neighbor list of u, then sort exploration order:
Sort rule 1: straight movement first
explore axis-aligned (up/down/left/right) neighbors before diagonal neighbors
Sort rule 2: straight-ahead first (directional continuity)
prioritize if parent->u entry direction matches u->v direction
(= prefer paths that go straight without turning)
visit neighbor v in sorted order:
if unvisited: dist[v] = dist[u] + 1, prev[v] = u
store v arrival direction (u->v) in pdx[v], pdy[v]
if v == g: backtrack prev chain to return path
otherwise insert v into queue
3. Path Reconstruction
prev[g] -> prev[prev[g]] -> ... -> s backtrack then reverse
Why straight-first matters:
Standard BFS returns any path among equal-distance paths.
On a grid, zigzag and straight paths may have equal distance.
Example (5x5 grid, A->B):
Standard BFS: A -> ↘ -> -> -> ↗ -> B (zigzag, same hops)
Straight-first: A -> -> -> -> -> B (straight, same hops)
Straight paths benefit message propagation:
- intermediate nodes have consistent forwarding direction
- path separation from biased paths (P+, P-) becomes clear
- overlap between 3 paths is minimized
8-neighbor traversal and Chebyshev distance:
Shortest distance with 8-directional movement on grid is Chebyshev distance:
One diagonal move = covers 1 vertical + 1 horizontal at once
Therefore BFS hop count = max(|r₁-r₂|, |c₁-c₂|)
100x100 grid (10,000 nodes): worst-case distance = 99 hops
Average distance ≈ 66 hops
Complexity:
Time: O(N) -- each node visited at most once, neighbor sorting is O(8 log 8) = O(1)
Space: O(N) -- dist, prev, pdx, pdy arrays
N = number of nodes in grid
6.5.3 Three-Path Routing (1 Shortest + 2 Biased)
Building on the shortest-path BFS, three independent paths are generated to ensure message delivery reliability.
Path P0: BFS shortest path (straight-ahead priority, 8-neighbor unweighted graph)
Path P+: left-biased path (detour by pushing midpoint left)
Path P-: right-biased path (detour by pushing midpoint right)
Biased path generation (Affine Waypoint):
Biased paths are generated by simply calling BFS twice, with an intermediate waypoint produced via affine transformation.
Biased path generation steps:
1. Progress vector d = (goal.c - start.c, goal.r - start.r)
2. Progress distance L = ‖d‖ = hypot(Δc, Δr)
3. Progress angle θ = atan2(Δr, Δc)
4. Convert straight midpoint (t=0.9 point) to local frame
[x_L, y_L] = R(-θ) × (t·Δc, t·Δr) ← inverse rotation: align progress axis to x-axis
5. Apply bias in normal (y-axis) direction
α = k × L × 0.2 ← bend strength (proportional to distance)
y_L += α ← push along local y-axis
6. Return to world coordinates
[dC, dR] = R(θ) × (x_L, y_L) ← forward rotation to restore original direction
mid = start + (dC, dR) ← absolute coordinates
7. Grid snap + boundary clamp
mid = snapClamp(mid) ← float → integer cell, correction within grid
8. Empty cell correction
if no peer in mid cell, adopt nearest valid cell within radius 3
$$\theta = \text{atan2}(\Delta r,\;\Delta c)$$
$$\alpha = k \times \|\vec{d}\| \times 0.2$$
$$\hat{n} = [-\sin\theta,\;\cos\theta]$$
$$p_m = p_s + t \cdot \vec{d} \;\pm\; \alpha \cdot \hat{n} \qquad (t = 0.9)$$
Final path composition:
P- = BFS(start → mid-) ⊕ BFS(mid- → goal)
Affine transformation order (identical to OpenGL's SRT matrix multiplication order):
S (Shear) : apply normal-direction bend (push by α)
R (Rotate) : rotate/inverse-rotate by progress angle θ
T (Translate): translate to start point coordinates
Order: local transform (inverse rotation → apply bend → forward rotation) → absolute coordinate translation
If this order is reversed, midpoint goes out of grid bounds
Path separation guarantee:
t = 0.9 positions midpoint at 90% of destination
→ probability of overlap with shortest path (P0) in start-to-midpoint segment is extremely low
→ 3 paths fan out on grid ensuring independence
+k (left) and -k (right) are symmetrically applied, so
P+ and P- split to both sides relative to P0
6.5.4 Directional Gossip
1. Sender node embeds direction vector u = (sx, sy) in message when sending to neighbors
2. Receiver selects only "forward neighbors" among 8 neighbors to relay
Forward condition: δ · u > 0 (dot product of movement vector and direction vector is positive)
3. Max fanout 3
Performance comparison (N=10,000 nodes, S=100):
Total Sends Latency Reproducibility
Shortest path: ~100 O(√N) deterministic
3-path propagation: ~336 O(√N) deterministic
Directional gossip: ~30,000 O(√N) deterministic
Traditional gossip: ~399,000 O(log N) non-deterministic
6.5.5 Operational Strategy
Normal: global signal delivery via 3 paths (minimum bandwidth)
Failure: activate directional gossip assist (ensure coverage)
Traditional: high peak/duplicate cost, not recommended for constant use
6.5.6 Proprietary DHT Peer Management — Outbound-Only Buckets
UBMS's DHT is an entirely proprietary design, not based on the Kademlia protocol.
It carries the DHT name only; the structure and behavior are fundamentally different.
XOR distance: upper 64 bits of SHA256(ip1) XOR SHA256(ip2)
Bucket structure: fixed count, log2(distance) based classification (Kademlia uses 160 k-buckets)
Bucket purpose: outbound only (manage connection targets, inbound handled separately)
Bucket size: significantly expanded compared to Kademlia's k=20
Sort criteria: XOR distance ascending, tiebreaker: IP lexicographic
Replacement: replace farthest peer (Kademlia retains oldest peer)
COW update: atomically snapshot-replace entire bucket via atomic shared_ptr
Rotating edges: Near/Far/Storage 3-type cache, 20-30% periodic refresh
Gossip dedup: hash set + FIFO queue (upper limit)
Key differences from Kademlia:
Kademlia UBMS DHT
160 k-buckets (per-bit) fixed-count buckets (log2 interval)
k=20 (20 per bucket) significantly expanded bucket capacity
bidirectional (request+response) outbound only
oldest peer priority closest XOR distance peer priority
FIND_NODE/STORE protocol grid + gossip + rotating edge combination
ping-pong based liveness check direct client validity check
Bucket count and bucket capacity are constants, adjustable based on network scale.
In this proprietary DHT, buckets are simply lists that classify peers by distance;
the patent-pending grid routing and directional gossip handle the core of message propagation,
so the DHT is limited to an auxiliary role in peer discovery.
6.6 Utilities (libubmsutil.so)
UBMS::Worker<T> template: a common pattern for queue-based worker threads.
add work via push(), process in process()
synchronous execution on worker thread via callSync() (promise/future)
60-second timeout safeguard
UBMS::QueueSafe<T>: a thread-safe queue based on condition_variable.
UBMS::Arith: overflow/underflow checks for uint64_t. Uses uint128_t intermediate values in mulDiv().
7. Multithreaded Safety
7.1 Lock Strategy
| Component | Lock Type | Read | Write |
| UBMS::CacheManager | shared_mutex | shared_lock (concurrent multiple) | unique_lock (exclusive) |
| UBMS::Chain | mutex | - | addBlock/rollBack serialized |
| UBMS::BlockCurrent | atomic shared_ptr + mutex | atomic load (no lock) | mutex-protected |
| UBMS::BlockMetaFullCache | atomic shared_ptr + mutex | atomic load (no lock) | COW swap |
| UBMS::BlockPool | atomic shared_ptr + mutex | atomic load (no lock) | COW swap |
| UBMS::VolatileCache | shared_mutex | shared_lock | unique_lock |
| UBMS::ConfirmedCache | shared_mutex | shared_lock | unique_lock |
| UBMS::TxCurrent | shared_mutex | shared_lock | unique_lock |
| DB | mutex | All operations serialized | All operations serialized |
7.2 TOCTOU Avoidance Design
Vulnerable design (split calls):
Thread A: isSpentKey(key) → false (unspent)
--- meanwhile Thread B consumes key via addBlock() ---
Thread A: addTx(key) → creates TX with already-spent UTXO (double-spend!)
UBMS solution: atomic check functions
checkDoubleSpendWithPool(address, key):
// CacheManager's shared_lock already held
// Step 1: check confirmed ledger spend status
// pass if TX pool change, otherwise reject
// Step 2: check TX pool spend (same address)
// reject if already reserved for spending
// Step 3: global cross-address double-spend check
// reject if another address's TX already used it
// unspent verification complete if all checks pass
Full list of atomic check functions:
| Function | Check Scope | Purpose |
checkDoubleSpendWithPool() | Confirmed + TX pool + global | Multi-stage double-spend check |
isNotSpentKeyWithPool() | Confirmed + TX pool change | Unspent verification |
getUTXOWithPool() | Confirmed + TX pool | Unified UTXO query |
getInputWithPool() | DB + volatile + TX pool | Input collection |
getBalanceAvailableWithPool() | DB + volatile + TX pool | Available balance |
getStakeWithPool() | DB + volatile + TX pool | Unified stake query |
Lock hierarchy design (deadlock prevention):
UBMS::Chain::m_mutex (std::mutex, exclusive) ← addBlock/rollBack serialization
└→ UBMS::CacheManager::m_mutex (shared_mutex) ← read/write separation
└→ UBMS::VolatileCache::m_mutex ← internal protection
└→ UBMS::ConfirmedCache::m_mutex ← internal protection
└→ UBMS::TxCurrent::m_mutex ← internal protection
Rule: acquire outer → inner only, never reverse (deadlock prevention at source)
7.3 Lock-Free Read Pattern
BlockCurrent, BlockMetaFullCache, and BlockPool are designed so that the read path can instantly obtain a snapshot of the current state without any locking. Writes are restricted to a single path, eliminating data races at the source while ensuring that readers never experience waiting or blocking.
7.4 TX Pool Double-Spend Prevention — 4-Stage Conflict Check
isConflict_(reserved, tx):
Check 1: TX internal input duplication
reject if same UTXO referenced twice within same TX
Check 2: per-address reservation pool double-spend
reject if UTXO already reserved by previous TX of same address
Check 3: global cross-address double-spend
reject if UTXO already used by another address's TX
→ m_globalSpentKeys (unordered_set, O(1) lookup)
Check 4: TX internal output index duplication
reject if same output index generated twice
TX Pool Reservation Pool (UtxoPool) Operation:
applyReserveAdd_(tx):
change returning to own address among outputs → add to available
input → register in spent_keys + m_globalSpentKeys
Effect:
when A sends 3 UBMS using 5 UBMS UTXO
→ spent_keys: {original 5 UBMS key}
→ available: {change 2 UBMS key} ← immediately usable in next TX
TX Pool Cleanup After Block Confirmation (3 stages):
1) syncCurrentTx(confirmedTxList) → remove confirmed TX by txid
2) removeConflictingCurrentTx(spentKeys) → remove conflicting unconfirmed TX
3) cleanupCurrentTxByHeight(minHeight) → remove too-old TX
8. Performance Analysis
The O() notation below represents time complexity. O(1) means constant time regardless of data volume; O(N) means time proportional to data volume.
8.1 Read Performance
| Operation | Path | Notes |
| Balance query | DB (owner index) + volatile filtering | O(UTXO count) |
| TX existence check | volatile (10 blocks) -> DB | Recent TXs served instantly from memory |
| UTXO spent check | volatile spentKeys -> DB | O(10) maximum |
| Recent TX query | volatile reverse -> DB | txid timestamp ordering |
| Referral query | ConfirmedCache memory | O(1) hash map |
8.2 Write Performance
| Operation | Cost | Notes |
| Block addition | O(TX count + UTXO count) | volatile pushBack |
| DB commit | O(delta size) | Once every 10 blocks, batch write |
| Rollback | O(1) | volatile popBack, DB untouched |
8.3 I/O Performance — Measured Benchmarks
Test environment: AMD Ryzen 7 2700X (released 2018), single-threaded (1 core), 3-second measurement, localhost
Measured on a single core of an 8-year-old CPU. On a same-generation Ryzen 9 3900X, single-core performance improved by over 30%
Throughput — Text Protocol
| Message Size | Clients | Throughput (msg/s) | Sent | Received |
| 32B | 1 | 1,195,757 | 3,587,433 | 3,587,271 |
| 32B | 10 | 10,132,692 | 60,851,192 | 30,398,077 |
| 256B | 1 | 883,132 | 2,649,581 | 2,649,396 |
| 256B | 10 | 4,284,165 | 27,230,564 | 12,852,496 |
| 1KB | 1 | 801,805 | 2,405,416 | 2,405,416 |
| 1KB | 10 | 1,628,376 | 8,246,630 | 4,885,129 |
| 4KB | 1 | 320,268 | 1,299,084 | 960,806 |
| 4KB | 10 | 205,166 | 1,706,216 | 615,498 |
Throughput — Binary Protocol
| Message Size | Clients | Throughput (msg/s) | Sent | Received |
| 32B | 1 | 1,431,783 | 4,295,670 | 4,295,349 |
| 32B | 10 | 9,755,885 | 74,314,915 | 29,267,656 |
| 256B | 1 | 1,231,194 | 3,693,694 | 3,693,584 |
| 256B | 10 | 5,260,272 | 31,169,940 | 15,780,817 |
| 1KB | 1 | 627,774 | 1,883,322 | 1,883,322 |
| 1KB | 10 | 1,709,745 | 8,647,578 | 5,129,235 |
| 4KB | 1 | 509,816 | 1,687,959 | 1,529,449 |
| 4KB | 10 | 447,800 | 2,172,084 | 1,343,400 |
Latency (64B echo, 1,000 iterations)
| Metric | Value |
| Average | 32.0 us |
| p50 | 32.0 us |
| p99 | 38.1 us |
| min | 28.1 us |
| max | 40.6 us |
Connection Speed
| Metric | Value |
| Connection speed | 12,419 conn/s |
| Total connections | 1,000 in 0.08s |
Measured Results Summary
The benchmarks above are actual measurements of libubmsio_uring.so itself; no controlled comparison against other libraries under identical conditions was performed. That said, 1.7 million msg/s for 1KB messages and 10.1 million msg/s for 32B messages on a single thread, with a p99 latency of 38us, demonstrate effective utilization of io_uring's kernel-level optimizations. These figures are notably high when compared against published benchmarks of epoll-based libraries such as libevent, libuv, and Boost.Asio.
Key measured figures:
- binary 1KB, 10 clients: 1,709,745 msg/s (single-thread)
- text 1KB, 10 clients: 1,628,376 msg/s (single-thread)
- 32B small messages, 10 clients: 10,132,692 msg/s
- p99 latency: 38.1us (64B echo RTT)
- connection speed: 12,419 conn/s (1,000 connections/0.08s)
- additional improvement confirmed with multi-core (20%+ on office hardware)
The kernel-level optimizations inherent to io_uring (SQE batch submission, kernel-side polling, reduced syscalls) are the primary driver of throughput. On top of this, libubmsio_uring.so combines multishot, zero-copy, provided buffers, and backpressure to form a network layer tailored for blockchain nodes.
The benchmark binary (ubmsio_uring_benchmark) is included in the build artifacts, so anyone can reproduce the above results under the same environment.
8.4 Memory Usage Estimate
VolatileCache ~50MB (10 blocks x 5MB/block)
TxCurrent ~100MB (pending TX + reservation pool)
BlockPool ~100MB (unconfirmed forks)
Total ~260MB (normal state)
DB several GB ~ hundreds of GB (block data)
8.5 Network Optimization
Message compression zlib (plaintext messages)
Message dedup message ID hashing + window-based dedup tracking
Public key caching LRU method (eliminates PEM parsing cost)
Batch sending sendmsg bulk send
9. Security Design
9.1 Build Security
Security flags are set globally in the top-level build script, automatically applied to all 11 submodules.
Compiler Security
- Buffer overflow runtime detection — Determines buffer sizes for standard library functions (memcpy, strcpy, etc.) at compile time and immediately terminates the process if exceeded at runtime
- Enhanced stack canaries — Inserts a random value (canary) in the function prologue to detect stack buffer overflow attacks before they overwrite the return address. Strong mode applies to all functions containing arrays or address references
- Stack-heap clash prevention — Blocks Stack Clash attacks that grow the stack in large increments to invade heap territory. Inserts page-granularity probes during stack extension so guard pages cannot be skipped
- Control flow integrity — Validates indirect calls (function pointers, virtual functions) and return addresses at the hardware level to block ROP/JOP attacks. Leverages Intel CET (Shadow Stack + IBT)
- Position-independent code — Generates all code as PIC to maximize ASLR (Address Space Layout Randomization) effectiveness, making memory address prediction infeasible for attackers
- Format string security — Treats cases where user input is used as a format string in printf-family functions as compile errors rather than warnings, eliminating format string attacks at the build stage
- STL container bounds checking — Enables bounds checking on index access for STL containers such as vector and string, immediately aborting on out-of-range access
Linker Security
- Full RELRO — Sets the GOT (Global Offset Table) to read-only and immediately resolves all symbols at program startup, blocking function hijacking attacks via GOT overwrites
- Stack execution prevention — Removes execute permission from the stack region, preventing injected shellcode on the stack from running
- Text relocation blocking — Prohibits writable relocations in the code segment, protecting shared library code regions from tampering
- Symbol hijacking prevention — Raises warnings when the same symbol is defined in multiple objects, detecting malicious symbol replacement
Additional Release Build Measures
- Debug symbol stripping increases the difficulty of binary reverse engineering
- RPATH is fixed to a relative path based on the executable, preventing library path manipulation
9.2 Cryptographic Security
RSA-4096 key pair sufficient key length
SHA-256 double hashing during address generation
HMAC-SHA256 message authentication
Base58Check address error detection via checksum
Zip Bomb defense decompression 64MB limit
9.3 Runtime Security
Arith overflow check prevent uint64_t range overflow during amount calculation
Signature duplication check window-based signature tracking
TOCTOU resolution atomic double-spend check
globalSpentKeys cross-address double-spend blocking
9.4 Serialization Safety
The describe() self-describing pattern in libubmstype.so auto-generates both serialization and deserialization from a single declaration. This eliminates security threats that can arise in the deserialization path at the framework level.
Vector size cap check prevent memory explosion from abnormal packet sizes
Buffer boundary check block access exceeding read range
Enum fallback handling apply safe default values for undefined values
Manual parsing code elimination eliminate deserialization vulnerabilities from developer mistakes at source
9.5 Test Infrastructure
Per-module unit tests are organized on GTest, with approximately 5,800 lines of test code. Some tests are currently awaiting updates due to an ongoing large-scale refactoring; they will be restored incrementally as the codebase stabilizes.
10. Design Strengths Summary
10.1 Cache Design
- 3-tier cache + TX pool unified under a single lock for atomic state inspection
- Rollback is O(1) (a single delta popBack), a different approach from Bitcoin's DisconnectBlock
- Confirmed data commits are batched every 10 blocks, minimizing DB write amplification
- BlockDelta isolates only the changed portion, enabling atomic apply/undo
- Pre-collecting spent UTXOs prevents orphaned indices during DB migration
- Three index types (owner/miner/txaddr) achieve O(N) per-address lookups
- TOCTOU avoidance: 6 atomic check functions structurally block double-spending
- Global spent keys in the TX pool detect cross-address double-spend attacks in O(1)
10.2 I/O Design
- Aggressively leverages io_uring's latest features (multishot, zero-copy, provided buffers)
- Reference counting + generation numbers for safe memory management in asynchronous contexts
- Backpressure control prevents memory exhaustion
10.3 Concurrency Design
- Shared locks enable read multiplexing, eliminating query bottlenecks
- Atomic shared pointer swaps allow lock-free reads (BlockCurrent, BlockPool, etc.)
- Worker queue pattern enables each function to operate on an independent thread
- Signal-slot pattern for loose coupling between modules
10.4 Data Design
- UTXO model makes balance calculation clear and verification straightforward
- describe()-based serialization with automatic dual-format support (JSON/binary)
- owner/miner/txaddr reverse indices optimize per-address lookups
- txid uses a timestamp prefix, enabling chronological queries without a separate time index
10.5 Network Design (Patented Technology)
- Deterministic 2D grid placement allows all nodes to reproduce the identical topology
- Affine-biased 3-path routing provides resilience against failures, congestion, and censorship
- Directed gossip reduces transmission volume to 1/13 of traditional gossip
- Performance vs. traditional gossip: 336 path propagations vs. 399,000 (N=10,000)
- Proprietary DHT (outbound-only buckets) for peer discovery without central servers
- Topology recalculated every 3 seconds for network adaptability
10.6 Economic Design (Tokenomics)
- Shifted Sigmoid reward curve prevents large staker dominance and ensures fairness for small stakers
- Miner 5% + Staker 95% on-chain automatic distribution
- PoB 5-tier distributor fee sharing (60/20/10/7/3%) incentivizes network growth
- Dynamic fee: \(EF = \sqrt{v/v_0} \times CF\) — rational fee based on external market price
- Burn mechanism: \(\max(0.01,\;\min(1,\;N/10{,}000))\) for automatic supply regulation
- Two-phase halving schedule (early phase: every 540 blocks with rapid decrease + late phase: 4-year cycle at 210,240 blocks)
11. Core Data Structures
UBMS::S_BLOCK (Block)
hash, previousHash, merkleHash, height, nonce, difficulty
transaction[], stakeReward[]
.
.
UBMS::S_TRANSACTION (Transaction)
type (NONE/LOCK/UNLOCK/REFERRAL)
txid, address, signature, publicKey
in[], out[], referral
.
.
UBMS::S_UTXO (Unspent Output)
txid, index, amount, owner
stake (NONE/LOCK/UNLOCK + minerAddress)
ubms (meta, TTL, conditions)
.
.
UBMS::BlockDelta (Block Delta)
height, hash, previousHash
addedUtxo{}, spentKeys{}, spentUtxoInfo{}
transactions[], addedReferrals[]
.
.
12. External Dependencies
| Library | Purpose | License | Notes |
| OpenSSL 3.x | RSA, SHA, HMAC, RNG | Apache 2.0 | EVP API |
| liburing | io_uring system interface | MIT / LGPL 2.1 | Linux 5.19+ |
| libevent | Event loop, signal-slot, HTTP server, OS signals, timers | BSD 3-Clause | Full replacement for Qt/Boost |
| DB | Persistent KV store | BSD 3-Clause | Bloom filter |
| jsoncpp | JSON parsing | MIT | |
| fmt | Formatted output | MIT | |
| zlib | Compression/decompression | zlib License | |
| libcurl | HTTP client | MIT/X inspired | For FCM notifications |
12.1 License Independence — A Clean Dependency Structure
Licensing issues are easy to overlook in blockchain projects, yet they become critical barriers at the commercialization stage.
In practice, a significant number of open-source blockchain projects indiscriminately pull in libraries carrying
copyleft licenses such as GPL, AGPL, or SSPL,
resulting in a patchwork of licensing obligations. In such cases, the entire project becomes subject to the terms of those licenses,
making commercial distribution, proprietary license conversion, and technology licensing either legally impossible or extremely complicated.
Every external dependency in UBMS is composed exclusively of permissive licenses:
Apache 2.0 free for commercial use, patent grant included
BSD 3-Clause free for commercial use, only copyright notice required on redistribution
MIT virtually unrestricted use
zlib License nearly unrestricted, only false attribution prohibited
What this composition means:
- Freedom to distribute commercially — Binaries can be distributed without any obligation to disclose source code
- Proprietary license conversion possible — The entire project can be converted to proprietary software
- Freedom to license technology — Dependency licenses pose no obstacle when licensing patented technologies (such as grid routing) to third parties
- Minimized fork risk — No risk of forced source disclosure due to GPL copyleft contamination
Particularly noteworthy is the complete removal of Qt (LGPL/GPL/commercial) and Boost (BSL-1.0) from the dependency chain.
Qt under LGPL imposes onerous conditions including dynamic linking obligations and user relinking guarantees,
while commercial licensing incurs annual costs of several thousand dollars.
UBMS replaced Qt's signal/slot mechanism and event loop with a single libevent (BSD) dependency,
thereby eliminating this licensing burden at its root.
The fact that all nine external dependencies carry permissive licenses is not coincidental — it is intentional by design.
This maximizes the project's legal freedom and means that investors or partners
can be presented with a clean codebase that imposes no license due diligence burden.
12.2 Potential for Growth as General-Purpose Libraries
In the process of building its blockchain node, the UBMS project produced several
general-purpose libraries with independent value as byproducts.
These libraries can be used as-is in general server applications unrelated to blockchain,
and ubmsnotify (a standalone FCM push notification server) serves as proof of this.
Libraries available for independent distribution:
libubmsio_uring.so io_uring-based high-performance network server/client framework
includes Server, Client, WebSocket, WebSocketClient, SafeCurl
immediately applicable to chat servers, IoT gateways, game servers, etc.
libubmsevent.so libevent-based event engine + async signal-slot + OS signal integration
build event-driven applications without Qt/Boost
libubmstype.so proprietary serialization engine (auto-generates JSON + binary from a single describe())
replaces protobuf/flatbuffers, no external code generation tools needed
libubmshttp.so REST API + reverse proxy + redirect + rate limiting
build HTTP services at application level without nginx
libubmscrypto.so RSA-4096, SHA-256, RIPEMD-160, Base58, HMAC, zlib integrated
easy-to-use crypto functions via OpenSSL EVP API wrapper
Since the license dependencies of all these libraries are permissive,
there are absolutely no legal barriers to distributing them as Ubuntu/Debian packages (apt)
or registering them on C++ package managers such as vcpkg or Conan.
Outlook:
- Contribution to the C++ server development ecosystem — A production-grade framework combining io_uring + libevent is rare in the open-source market
- Project brand expansion — When a blockchain project distributes general-purpose infrastructure tools, developer community trust and project recognition rise simultaneously
- Technology monetization pathway — Commercial support/consulting for the libraries themselves, or technology partnerships mediated through the libraries
- Talent acquisition — General-purpose open-source libraries are the most effective means of attracting external contributors, which in turn cycles back to improve the quality of the blockchain core
13. Block Validation Flow
UBMS::Chain::addBlock(target)
|
+--> UBMS::Chain::m_mutex.lock()
|
+--> UBMS::InspectManager::validateBlock()
| +--> hash verification
| +--> previous hash verification
| +--> merkle root verification
| +--> difficulty verification
| +--> timestamp verification
|
+--> UBMS::InspectManager::validateBlockTxSignatures()
| +--> verify each TX signature
|
+--> UBMS::InspectManager::validateBlockInputsNotSpent()
| +--> check input UTXO spend status
|
+--> UBMS::CacheManager::addBlock()
| +--> makeDelta() (extract changes)
| +--> volatile.pushBack(delta)
| +--> confirmed.updateNodeInfo()
| +--> confirmed.addReferral()
| +--> DB commit on overflow
|
+--> BlockMetaFullCache update
+--> BlockCurrent replace
+--> remove from BlockPool
|
+--> Chain::m_mutex.unlock()
14. Conclusion
UBMS (UTXO-Based Metadata Smart Chain) is a 100% independently developed blockchain full-node system,
guided by the vision of "Perpetual Evolution: A Blockchain That Never Stops."
Comprising hundreds of header/implementation files, 11 library modules + a daemon + a standalone notification server,
the entire system was built using standard C++ and a minimal set of permissively licensed libraries, without any external frameworks (Qt, Boost).
The following is a summary of all technical domains analyzed in this report.
Consensus Design (Sections 3, 5)
- Triple consensus via PoW + PoS + PoB achieves both security and fairness simultaneously
- Fully decentralized consensus without a beacon chain (minimum 9 nodes)
- Shifted Sigmoid algorithm prevents large staker monopolization: \(R(x) = \frac{1}{1+e^{-z}}\)
- Two-phase halving schedule (early phase: 540-block rapid decrease + late phase: 210,240-block 4-year cycle), total supply approximately 21,012,500 UBMS
- InspectManager-based block validation pipeline: sequential verification of hash, previous hash, Merkle root, difficulty, timestamp, TX signatures, and UTXO spend status (Section 13)
Economic Design (Section 3)
- On-chain automatic distribution: 5% to miners + 95% to stakers
- PoB 5-tier distributor fee allocation (60/20/10/7/3%) incentivizes network growth
- Dynamic fee: \(F = 1{,}000 \times \sqrt{v/10{,}000} \times CF\)
- Burn mechanism: \(\text{PoS dist. rate} = \max(0.01,\;\min(1,\;N/10{,}000))\) for automatic supply regulation
- UTXO-based metadata smart contracts (native C++ execution without VM, TTL/conditional execution support)
Network Design — PSAN (Sections 4, 6.5)
- Polymorphic Self-Adjusting Network (PSAN) prevents message flooding
- Deterministic 2D grid + affine-biased 3-path routing achieves 1/1000 bandwidth reduction compared to traditional gossip (patented technology)
- Directed gossip: path propagation 336 vs. traditional gossip 399,000 (N=10,000)
- \(\log_2(N)\)-based automatic Blueprint calculation: \(R = \max(3,\;\lfloor\log_2(N)/2\rfloor \times 2+1)\), \(V = \max(5,\;\lfloor\log_2(N)/1.2\rfloor \times 2+1)\)
- Proprietary DHT (outbound-only, SHA-256 XOR distance): shares only the name with Kademlia — fundamentally a distinct proprietary design
- Topology recalculation every 3 seconds for network adaptability
Cache and Data Design (Sections 3, 10, 11)
- Three-tier cache (VolatileCache + ConfirmedCache + DB) + TX pool unified under a single lock for atomic state inspection
- Block deltas isolate only the changes, enabling O(1) rollback (a single delta popBack)
- Confirmed data commits are batched every 10 blocks to minimize DB write amplification
- Three index types — owner/miner/txaddr — optimize per-address lookups
- txid timestamp prefix enables latest-first queries without a separate time index
- UTXO model provides clear balance calculation and straightforward verification
Foundation Libraries (Section 6)
- io_uring (libubmsio_uring.so) — Multishot Accept/Recv, Zero-Copy Send, Provided Buffer Ring, Fixed FD, Batch Submit, Backpressure control. Generation number (gen) safely ignores stale CQEs
- Event Architecture (libubmsevent.so) — A single libevent replaces Qt signal/slot, Boost.Asio event loop, and Boost.Signals2 observer pattern entirely. event_new + timeval{0,0} for immediate async dispatch, COW slot snapshots, 3-state CAS (Alive/Marked/Cleaning) lifetime management
- HTTP Server (libubmshttp.so) — Router (method+URI routing) + Forwarder (reverse proxy, ROUNDROBIN) + Redirector (301/307/308) + Abuse (LRU rate limiting). Application-level HTTP services without nginx
- Serialization Engine (libubmstype.so) — A single describe() automatically generates dual formats: JSON + little-endian binary. Safe deserialization with vector size caps, buffer boundary checks, and enum fallback
- Cryptography (libubmscrypto.so) — RSA-4096, SHA-256, RIPEMD-160 (independent implementation), Base58Check, AES-GCM, HMAC-SHA256, zlib (Zip Bomb defense 64MB)
Multithreaded Safety (Section 7)
- Systematic locking strategy across 9 components: shared locks, atomic shared pointers + COW, exclusive lock serialization
- TOCTOU avoidance: 6 atomic check functions including checkDoubleSpendWithPool structurally prevent double spending
- TX pool 4-stage collision check: intra-TX duplicate, per-address reservation pool, global cross-address (global spent keys), output index duplicate
- Lock-free reads via atomic shared pointers (current block, block meta full cache, block pool)
- Lock hierarchy design: chain exclusive lock -> cache manager shared lock -> internal locks acquired only in this order, reverse order prohibited (deadlock prevention at the root)
Performance (Section 8)
- io_uring measured benchmarks: multishot, zero-copy, provided buffers maximize I/O
- Queries: latest TX served instantly from memory, referral O(1) hash map, UTXO spend check O(10) maximum
- Network: zlib compression, message ID deduplication, public key LRU caching, sendmsg batch transmission
Security Design (Section 9)
- Build level: FORTIFY_SOURCE, Stack Canary, Stack Clash Protection, CFI, Full RELRO, ASLR (fPIC), noexecstack
- Cryptography: RSA-4096, SHA-256 double hashing, HMAC-SHA256, Base58Check, Zip Bomb defense
- Runtime: Arith overflow checks, signature deduplication (window-based), atomic TOCTOU resolution, global spent keys cross-address blocking
License Independence and Versatility (Section 12)
- All 9 external dependencies carry permissive licenses (Apache 2.0, BSD 3-Clause, MIT, zlib): commercial distribution, proprietary license conversion, and technology licensing all possible without source disclosure obligations
- Complete removal of Qt (LGPL/GPL/commercial) and Boost from dependencies eliminates licensing burden at the source
- libubmsio_uring.so, libubmsevent.so, libubmstype.so, libubmshttp.so, and libubmscrypto.so can be distributed as independent libraries unrelated to blockchain
- ubmsnotify (standalone FCM push notification server) demonstrates the libraries' general-purpose applicability
- No legal barriers to Ubuntu/Debian apt packages or vcpkg/Conan registration
In the course of building its blockchain node, UBMS independently designed every layer —
consensus, network, cache, I/O, events, serialization, and security — without external frameworks,
and the libraries produced in this process hold value as general-purpose server infrastructure beyond blockchain.
15. Development Timeline
15.1 Conception Phase (2022 – 2024.10)
- 2022 — UBMS conception begins. UTXO-based metadata smart chain concept established, design documents drafted, consensus model and economic structure designed, development environment set up
- 2024.11 — Full-scale development commences. Principle of standard C++ libraries + minimal external dependencies established
15.2 Prototype Phase (2025.2 – 2025.4)
- 2025.2 — PSAN (Polymorphic Self-Adjusting Network) concept publicly unveiled. A proprietary topology design combining role-based routing on a deterministic 2D grid. PoB (Proof of Behavior) 5-tier distributor allocation mechanism finalized. Open beta schedule announced
- 2025.3 — PSAN operational proof achieved. Grid coordinate assignment between nodes, affine-biased 3-path routing, and directed gossip confirmed to work as designed. Codebases of major coins listed on leading Korean exchanges (Upbit) surveyed to verify UBMS's originality
15.3 Public Testing Phase (2025.5 – 2025.7)
- 2025.5 — Roadmap published. First edition of the whitepaper completed. Open test launched, external node participation begins
- 2025.6 — Shifted Sigmoid reward algorithm discovered and applied.
Derived from the developer's experience in RNN/GRU-based AI development, applying the sigmoid function's characteristics to reward curves —
an original approach not previously used in existing blockchains.
\(R(x) = \frac{1}{1+e^{-z}}\), \(z = ((x + T \times 0.2)/T - 0.5) \times 10\).
Public beta response exceeded expectations, prompting the decision to outsource iOS wallet app development.
TLS applied, P2P protocol stabilization patches deployed
- 2025.7 — PSAN shuffle bias improved. Transition from SHA-256 + XOR to HMAC-SHA256 + XOR reduced node distribution bias from +/-8% to +/-1-2%
15.4 Pre-production Phase (2025.8 – Present)
- 2025.8 — Pre-production preparation complete. Five programs finalized: ubmsdaemon (full node), ubmsmine (miner), ubmsmine_and (Android wallet), ubmscli (CLI), ubmsnotify (notification server). Load balancer demonstration verified multi-node operation
- 2025.9 — Pre-production launched. Light node completed, expanding mobile participation.
Shifted Sigmoid slope coefficient adjusted from 10 to 7 to optimize the reward curve for small stakers.
On the third day of pre-production, a policy limiting each node to one stake was introduced — a case where the scenario of monopolizing rewards through multiple stakes was discovered in live operation and addressed immediately
- 2025.10 — Patent application filed for deterministic 2D grid routing technology
- 2025.12 — Major architecture update. Complete topology redesign, directed gossip optimization, three-tier caching structure refinement. The current cache + block delta + rollback architecture was established at this point
- 2026.1 — Server infrastructure update. Rollback mechanism design-verified and reinforced
- 2026.2 — Whitepaper v1.9 published. Burn criteria changed from staker count to node count, transitioning to a network-participation-based economic model.
3D grid extension concept unveiled — a research direction combining the existing 2D grid (8 neighbors) expanded to 3D (26 neighbors) with SNN (Spiking Neural Network)-based AI models
- 2026.3 — iOS wallet app released. Wallet availability achieved across both Android and iOS platforms
15.5 Current Network Status
- Active nodes: 148
- Block height: #29,431
- Mined supply: 9.67%
- Burned supply: 5.11%
- Circulating supply: 4.56% (mined 9.67% - burned 5.11%)