요약
여러 개의 시간 제한이 있는 기회를 가진 트레이더라는 상황을 상상해 보세요. 세 개의 차익거래 기회를 동시에 발견했지만, 한 번에 하나의 거래만 제출할 수 있습니다. 세 번째 거래가 처리될 때쯤이면 해당 기회는 사라집니다. 이것이 바로 순차성 문제입니다. 저희는 블록체인 시스템에서 보안과 기존 지갑과의 호환성을 유지하면서 병렬 거래 제출을 가능하게 하는 새로운 솔루션인 Nonce Bitmap을 제안합니다.
- 병렬 처리 . Nonce Bitmap은 기존 Nonce 필드에서 활용도가 낮은 비트를 활용하여 사용자가 최대 256개의 트랜잭션을 병렬로 전송할 수 있도록 하는 비트맵 기반 접근 방식을 도입합니다.
- 최소한의 저장 오버헤드 . Nonce Bitmap은 다른 접근 방식에 비해 최소한의 저장 오버헤드(주소당 32바이트)만 필요합니다.
- 이전 버전과의 호환성 . 기존 지갑과 일반 사용자는 동작에 변화가 없습니다.
- 재생 보호 . Nonce Bitmap은 순차적 병목 현상을 제거하는 동시에 재생 공격에 대한 보안을 보장합니다.
- 더 나은 UX/DX . Nonce Bitmap은 트레이더, MEV 검색자, 동시 거래 제출이 필요한 프로토콜 등 고빈도 사용자에게 특히 유용합니다.
전통적인 Nonce 메커니즘
EVM Nonce: 단순한 카운터 이상
기본적으로 논스는 각 외부 소유 계정(EOA)과 연결되어 해당 계정에서 전송된 거래 수를 나타냅니다. 각 StateAccount는 최대 8바이트의 논스 필드를 유지합니다.
// StateAccount is the Ethereum consensus representation of accounts. // These objects are stored in the main account trie. type StateAccount struct {Nonce uint64 Balance *uint256.IntRoot common.Hash // merkle root of the storage trie CodeHash [] byte }새 계정의 경우, 논스는 0부터 시작하여 해당 계정에서 발생한 거래가 블록에 포함될 때마다 1씩 증가합니다. 겉보기에는 간단해 보이지만, 이 카운터는 EVM의 무결성과 결정론적 운영에 필수적인 중요한 기능을 수행합니다.
보안 . 논스는 특정 주소에서 발생하는 각 거래가 고유한 논스를 사용하도록 요구함으로써 재전송 공격을 방지하는 데 사용됩니다. 따라서 네트워크가 해당 논스 사용을 승인했기 때문에 동일한 거래를 두 번 다시 제출하려는 시도는 실패합니다. 이러한 보안 보장은 블록체인에서 사용자 자산과 상호작용의 안전을 보장하는 데 필수적입니다.
순서 . 이더리움의 논스는 엄격하게 증가합니다. 즉, 각 트랜잭션은 이전 트랜잭션의 논스보다 하나 더 큰 논스를 가져야 합니다.
next := opts.State.GetNonce(from) if next > tx.Nonce() { return fmt.Errorf( "%w: next nonce %v, tx nonce %v" , core.ErrNonceTooLow, next, tx.Nonce())} // Ensure the transaction doesn't produce a nonce gap in pools that do not // support arbitrary orderings if opts.FirstNonceGap != nil { if gap := opts.FirstNonceGap(from); gap < tx.Nonce() { return fmt.Errorf( "%w: tx nonce %v, gapped nonce %v" , core.ErrNonceTooHigh, tx.Nonce(), gap)}}거래 계산 . 이는 이더리움 옐로페이퍼 에 논스의 정의로 명시되어 있지만, 이는 단지 현재 논스 설계의 함의일 뿐입니다.
Nonce . 이 주소에서 보낸 거래 수와 동일한 스칼라 값입니다. 또는 관련 코드가 있는 계정의 경우 이 계정에서 생성한 계약 수와 동일합니다.
현재 디자인에서는 주어진 주소에 대한 거래 계산(
eth_getTransactionCount)은 현재 계정의 nonce를 반환하는 것만으로 수행됩니다.// GetTransactionCount returns the number of transactions the given address has sent for the given block number func (s *TransactionAPI) GetTransactionCount(ctx context.Context, address common.Address, blockNrOrHash rpc.BlockNumberOrHash) (*hexutil.Uint64, error ) { // Ask transaction pool for the nonce which includes pending transactions if blockNr, ok := blockNrOrHash.Number(); ok && blockNr == rpc.PendingBlockNumber {nonce, err := sbGetPoolNonce(ctx, address) if err != nil { return nil , err} return (*hexutil.Uint64)(&nonce), nil } // Resolve block number and use its state to ask for the nonce state, _, err := sbStateAndHeaderByNumberOrHash(ctx, blockNrOrHash) if state == nil || err != nil { return nil , err}nonce := state.GetNonce(address) return (*hexutil.Uint64)(&nonce), state.Error()}
전반적으로 이 디자인은 재생 공격에 대처하는 간단하면서도 효과적인 방법을 제공하여 효율적인 거래 검증을 가능하게 하고 저장 공간을 줄입니다.
순차성 병목 현상
현재의 논스 설계는 계정 수준에서 불가피한 순차성을 야기합니다. 즉, 트랜잭션 n+1 n + 1 과 n n이 서로 관련이 없고 병렬로 실행될 수 있는 경우에도, 트랜잭션 n+1 n + 1 은 트랜잭션 n n 을 기다려야 합니다. 동일한 발신자의 트랜잭션은 논스 순서대로 처리되기 때문입니다.
거래 중단은 또 다른 문제입니다. 사용자가 블록에 포함되기에는 가스 가격이 너무 낮은 거래 n n 을 제출하면, 해당 거래는 블록에 포함되거나, 삭제되거나, 교체될 때까지 메모리 풀에 보류 상태로 남습니다. 이 기간 동안 해당 사용자의 후속 거래 제출 시도는 가스 가격과 관계없이 실패합니다. 이는 바람직하지 않으며 사용자에게 부정적인 경험을 초래합니다.
- 예를 들어, 사용자가 비교적 낮은 수수료로 보류 중인 ETH 이체 거래를 진행하다가 곧 청산될 DeFi 포지션을 긴급히 정리해야 할 수 있습니다. 현재의 논스 설계에서는 해당 거래가 중단될 때까지 기다리거나, 동일한 논스를 사용하지만 가스 가격이 더 높은 다른 거래로 대체해야 합니다. 어느 쪽이든, 이는 일반 사용자가 감당하기 어려울 만큼 복잡한 문제를 야기합니다.
게다가, 고급 사용자(예: HFT 거래자)는 종종 병렬로 트랜잭션을 전송해야 합니다. 이를 위해 오프체인에서 논스를 신중하게 관리해야 하는 경우가 많습니다. 하지만 이는 항상 쉬운 작업은 아닙니다. 오프체인 관리를 사용하더라도, 현재 트랜잭션을 제출하기 위해서는 1) 현재 논스 또는 2) 이전 트랜잭션 수신 정보를 쿼리해야 합니다. 지연 시간이 중요한 경우, 이러한 쿼리 역시 지연을 발생시킵니다. 특히 RISE, MegaETH, Monad, Flashblocks와 같이 트랜잭션 처리 속도가 매우 빠른( <10ms 분쇄 시간 ) 블록체인에서 온체인 데이터 쿼리는 수십에서 수백 밀리초의 지연을 초래할 수 있습니다.
더 심각한 문제는, 서로 다른 nonce를 사용하더라도 여러 트랜잭션을 병렬로 전송하려고 하면 잘못된 nonce 갭 오류가 발생할 수 있다는 것입니다. 이는 현재 P2P 전파 방식이 nonce n n 을 가진 트랜잭션이 트랜잭션 n+1 n + 1 보다 먼저 노드의 메모리 풀에 도착하도록 보장하지 않기 때문입니다.
이러한 제한은 지연 시간이 짧은 체인에서 특히 심각해집니다.
다른 시스템이 이 문제를 어떻게 해결하려고 시도했는지 살펴보겠습니다.
순차성 깨기
고성능 체인은 매우 낮은 지연 시간으로 수만 TPS를 처리할 수 있습니다. 하지만 더 나은 지갑/클라이언트 UX 없이는 그 활용도를 완전히 달성할 수 없습니다. 이러한 체인은 여러 트랜잭션을 동시에 처리할 수 있지만, 현재 트랜잭션 제출은 순차적이어서 잠재력을 최대한 발휘하는 데 병목 현상이 발생할 수 있습니다.
이 섹션에서는 이러한 순차성을 해결하기 위한 몇 가지 잠재적인 대안 설계를 살펴봅니다. 이러한 설계는 주로 논스(nonce)의 보안 측면에 초점을 맞추는데, 논스는 재전송 공격 방지를 위해 한 번 사용되는 숫자 입니다.
거래 순서 지정 및 계산은 중요하지만, 다양한 접근 방식을 통해 구현할 수 있습니다. 예를 들어, 이 eth_getTransactionCount 사용하는 서비스(일반적으로 탐색기)는 로컬 데이터베이스를 사용하여 이 값을 추출할 수 있습니다.
랜덤 논스
논스를 엄격하게 늘리는 대신, 이 설계는 트랜잭션이 임의의 고유 식별자를 포함하도록 하여 병렬 트랜잭션 제출 및 처리를 가능하게 합니다. 각 계정은 단일 스칼라 카운터가 아닌 이전에 사용된 모든 논스에 대한 기록을 유지합니다. 예를 들어, 이는 주소에서 사용된 논스 집합으로의 매핑으로 표현될 수 있습니다.
UsedNonces = map [Address] map [ uint64 ] bool트랜잭션이 제출되면 노드는 해당 계정에서 이미 사용되었는지 확인하여 논스의 유효성을 검증합니다. 논스가 사용되지 않은 경우, 트랜잭션은 승인되고 논스는 사용됨으로 표시됩니다.
이 접근 방식을 사용하면 처리 노드가 동일한 사용자의 트랜잭션(관련 없는 경우)을 병렬로 실행하여 성능을 크게 향상시킬 수 있습니다. 클라이언트 측에서는 지갑이 논스 카운터를 신중하게 추적하거나 동기화할 필요 없이 무작위 논스를 생성할 수 있으므로 병렬 트랜잭션 제출이 더욱 용이해집니다. eth_usedNonces 와 같은 추가 RPC를 구현하여 주어진 주소에 대해 사용된 논스를 검색할 수 있습니다. 또한, eth_getTransactionCount 는 주어진 주소에 대한 UsedNonces 의 길이를 반환할 수 있습니다.
그러나 이러한 접근 방식은 상당한 단점을 야기합니다. 가장 눈에 띄는 단점은 노드가 계정당 잠재적으로 큰 규모의 사용된 논스(nonce) 세트를 저장하고 유지해야 하는 저장 오버헤드로, 이로 인해 상태 크기와 저장 복잡성이 증가합니다. 또한, 무작위 논스 생성 알고리즘에 따라 논스 중복이 발생할 수 있습니다.
Hyperliquid의 디자인
Hyperliquid는 특정 주소에 사용된 모든 논스를 저장하는 대신, 주소당 가장 많이 사용된 100개의 논스만 저장하며, 논스 재사용을 확인하기 위한 추가 규칙을 요구합니다. 즉, 새 트랜잭션은 이 집합에서 가장 작은 논스보다 큰 논스를 가져야 하며, 이전에 사용된 적이 없어야 합니다(즉, 집합에 존재하지 않아야 합니다). 또한, 논스는 해당 트랜잭션이 포함된 블록의 UNIX 밀리초 타임스탬프로부터 1일 이내에 있어야 합니다. 예를 들어, 새 트랜잭션의 경우 논스를 현재 타임스탬프로 설정할 수 있습니다.
랜덤 논스 설계와 유사하게 Hyperliquid는 뛰어난 병렬성을 제공합니다. 지갑에서 다양한 논스 전략을 유연하게 선택할 수 있고, 병렬 트랜잭션 제출도 가능해짐에 따라 UX도 개선되었습니다. 시간 제한적인 유효성은 공격 릴레이 가능성을 줄여줍니다. 랜덤 논스 설계와 비교했을 때, 이 방식은 사용된 논스를 100개만 저장하므로 저장 오버헤드가 적습니다. 하지만 100개 이상의 트랜잭션을 병렬로 전송할 수 없다는 병목 현상이 발생합니다.
그러나 논스 관리 방식이 완전히 다르기 때문에 특정 작업은 기존 지갑과 호환되지 않을 수 있습니다. 실제로 이 논스 설계는 HyperCore 계층에만 사용됩니다. HyperEVM 계층은 여전히 기존 논스 설계를 사용합니다. 또한, 시간 제한 요건은 예약된 트랜잭션의 기간도 제한합니다. 즉, 하루 이상 동안 진행되도록 예약된 사전 서명된 트랜잭션은 불가능합니다.
2D 논스
RIP-7712는 계정 추상화 (AA) 트랜잭션을 위한 2차원 논스(2D 논스) 메커니즘을 도입합니다. 2D 논스는 스마트 컨트랙트 계정이 더욱 유연하고 병렬화된 논스 시스템을 처리할 수 있도록 합니다. 2D 논스는 n n 비트(예: AA에서는 n=256 , n = 256 ) 값으로, 두 개의 논리적 구성 요소로 나뉩니다.
┌─────────────────────────────────┬──────────────────────────┐│ Upper k bits │ Lower nk bits ││ (Nonce Key) │ (Nonce Sequence) │└─────────────────────────────────┴──────────────────────────┘- nonceKey .
nonceKeynonce 공간을 여러 개의 독립적인 카테고리로 분할하는 nonce 카테고리 역할을 합니다.- 클래식 nonce는 단일 nonce 카테고리(즉,
nonceKey = 0)를 갖는 것과 동일한 1D nonce에 해당합니다.
- 클래식 nonce는 단일 nonce 카테고리(즉,
- nonceSequence .
nonceSequence순서를 정하기 위해 순차적으로 증가해야 하는 해당 카테고리 내의 카운터입니다.
서로 다른 nonceKeys 가진 트랜잭션은 어떤 순서로든 실행되거나 포함될 수 있어 병렬 처리가 가능합니다. 반면, 동일한 nonceKey 가진 트랜잭션은 nonceSequences 증가시키면서 순차적으로 실행되어야 합니다.
nonceKey 계정의 병렬 처리 정도를 결정합니다. k k 가 클수록 병렬로 전송할 수 있는 트랜잭션 수가 늘어납니다. 이론적으로 이 구조를 사용하면 계정은 최대 2^{k} 2 k 개의 카테고리를 유지할 수 있으며, 각 카테고리는 2^{nk} 2 n − k 개의 순차적인 nonce를 보유할 수 있습니다. 즉, 계정은 nonce 순서에 관계없이 최대 2^{k} 2 k 개의 트랜잭션을 동시에 전송할 수 있습니다.
그러나 nonceKey 주로 관련 트랜잭션 그룹(예: 세션 키, 시간 기반)의 식별자로 사용됩니다. 이러한 방식으로 사용하면 동일 그룹 내의 트랜잭션을 병렬 처리할 수 없습니다. 예를 들어, nonceKeys 1, 2, 3이 각각 스왑, ETH 전송, ERC-20 전송에 사용되는 경우, 계정은 스왑 트랜잭션 두 개, ETH 전송 두 개, ERC-20 전송 두 개를 동시에 전송할 수 없습니다. nonce 관리와 관련하여 스왑 트랜잭션 하나, ETH 전송 하나, ERC-20 전송 하나만 동시에 전송할 수 있습니다. 또한, 새로운 nonceKey 추가될 때마다 nonceKey 와 nonceSequence 저장하기 위해 n n 비트의 저장 오버헤드가 발생합니다.
Nonce 비트맵 제안
이 섹션에서는 계정이 최대 256개의 트랜잭션을 병렬로 전송할 수 있도록 하는 새로운 논스 관리 메커니즘을 제안합니다. 병렬 트랜잭션당 1비트 이상의 저장 오버헤드가 발생합니다. 더욱이, 이 제안은 이전 버전과 완벽하게 호환되며 트랜잭션 제출 프로세스에 추가 필드를 도입하지 않습니다.
설계
저희 솔루션은 표준 계정 상태를 확장하여 기존 nonce와 Bitmap 필드를 결합하여 nonce 사용을 추적합니다. 각 Nonce 값에 대해 서로 다른 Index 가진 최대 256개의 트랜잭션을 허용합니다. Bitmap 필드는 256비트 필드이며, 각 비트는 현재 Nonce 에서 병렬 트랜잭션을 위한 256개의 사용 가능한 슬롯(각 슬롯은 Index 에 해당) 중 하나를 나타냅니다. 트랜잭션이 Nonce 를 수정하면 Bitmap 필드는 지워지고 Index 위치의 비트는 1로 설정됩니다.
// NonceBitmapStateAccount is the Ethereum consensus representation of accounts accommodating with nonce bitmap. // These objects are stored in the main account trie. type NonceBitmapStateAccount struct {Nonce uint64 // Anchor nonce: the last finalized sequential checkpoint, always have first 8 bits as 0s. Balance *uint256.IntRoot common.Hash // merkle root of the storage trie CodeHash [] byte Bitmap *uint256.Int // NEW: Tracks used slots for parallel transactions; nil for legacy accounts } 구체적으로, Nonce 는 기존 구현 방식과 마찬가지로 계속 증가합니다. 그러나 Nonce 의 처음 8비트는 항상 0입니다. 현재 Nonce 값은 64비트이며, 계정에서 이 값을 절대 사용하지 않을 것으로 예상됩니다. 64비트 Nonce 값은 최대 2^{64} = 18446744073709551616 2 64 = 18446744073709551616 개의 값을 사용할 수 있으며, 계정에서 하루에 10억 건의 거래를 전송하는 경우 모든 Nonce를 사용하는 데 5천만 년 이상이 걸리기 때문입니다. 따라서 계정에 56비트 공간( 2^{56} = 72057594037927936 2 56 = 72057594037927936 개 값)이 충분하다고 판단합니다.
Bitmap 의 각 비트는 해당 비트의 인덱스가 이미 사용되었는지 여부를 나타냅니다. 예를 들어, 인덱스 10의 비트맵이 1로 설정되면 인덱스 10이 현재 Nonce 에 사용되었음을 의미합니다. 256비트 Bitmap 필드를 사용하면 계정에서 한 번에 최대 256개의 트랜잭션을 원하는 순서대로 전송할 수 있습니다(엄격한 순서 지정은 필요 없음). Bitmap 사용하면 인덱스 사용 여부를 매우 효율적으로 확인할 수 있습니다. 또한, 이 방식은 병렬 트랜잭션당 1비트만 추가로 필요합니다.
거래 생성
핵심 과제는 기존 거래 형식을 손상시키지 않고 선택한 병렬 슬롯을 신호로 전달하는 것입니다. 사용자가 새 거래를 생성할 때 병렬 거래 전송을 지원하기 위해 Index 구성할 수 있어야 합니다. 한 가지 순진한 방법은 기존 거래 유형에 새로운 8비트 Index 변수를 도입하는 것입니다. 이 Index 필드는 발신자 계정 상태에서 Bitmap 필드의 해당 비트 값을 찾는 데 사용됩니다.
// LegacyTx is the transaction data of the original Ethereum transactions. type LegacyTx struct {Nonce uint64 // nonce of sender account GasPrice *big.Int // wei per gas Gas uint64 // gas limit To *common.Address `rlp:"nil"` // nil means contract creation Value *big.Int // wei amount Data [] byte // contract invocation input data V, R, S *big.Int // signature values ~~Index uint8 ~~ // NEW: The index value for parallelism? } 다행히 새로운 필드를 추가하지 않고도 Index 정보를 트랜잭션에 실제로 통합하는 더 나은 방법이 있습니다. 64비트 Nonce 필드의 방대하고 활용도가 낮은 공간을 활용하는 비트 패킹 기법을 사용하여 이 문제를 해결합니다. 이는 트랜잭션 내 Nonce 필드를 논리적으로 두 부분으로 분할하고, 간단한 비트 연산을 통해 추출하는 방식으로 수행됩니다.
func ExtractNonce (nonce uint64 ) (index uint8 , actualNonce uint64 ) {index = uint8 (nonce >> 56 ) // Extract first 8 bits (most significant bits) actualNonce = nonce & 0x00FFFFFFFFFFFFFF // Mask lower 56 bits return }-
Nonce의 처음 8비트는Index로 사용됩니다. - 마지막 56비트는 실제 nonce 값으로 사용됩니다. 위에서 분석했듯이, 56비트 nonce 공간은 모든 계정에 충분합니다.
일반 사용자의 경우 처음 8비트는 항상 0입니다. actualNonce 는 익숙한 순차적 nonce입니다. 일반 사용자의 관점에서는 전체 시스템이 변경되지 않은 것처럼 보입니다. 고급 사용자의 경우 처음 8비트를 원하는 값으로, 원하는 순서대로 설정할 수 있습니다. 따라서 고급 사용자는 최대 256개의 트랜잭션을 병렬로 전송할 수 있습니다.
Nonce 검증
검증 로직은 시스템의 핵심으로, 보안과 진행을 보장합니다. 새로운 거래가 수신되면 다음 로직이 실행됩니다(수수료 대체 거래는 여기서 고려하지 않습니다).
func ValidateNonce (account *NonceBitmapStateAccount, txPackedNonce uint64 ) bool {index, actualNonce := ExtractNonce(txPackedNonce) if actualNonce == account.Nonce + 1 { // --- CASE 1: Advancing the Sequence --- // This transaction is the next in the sequential chain. // It is valid. This will cause the account's Nonce to increment. // The bitmap is reset, as we are moving to a new base state. return true } else if actualNonce == account.Nonce { // --- CASE 2: Parallel Transaction --- // This transaction operates at the current account's Nonce. // Check if the requested parallel slot is available. if account.Bitmap == nil { // Bitmap is not initialized; this is the first parallel tx at this nonce. return true } return account.Bitmap.Bit( int (index)) == 0 // True if the slot is free } else { // --- CASE 3: Invalid Nonce --- // actualNonce is either too old (less than account's Nonce) or has a gap. // This mirrors the existing Ethereum validation rule. return false }} 다음 트랜잭션 시퀀스를 고려해 보겠습니다. 현재 Nonce 가 5이고 Bitmap 에 슬롯 0이 이미 사용 중이라고 표시된 계정으로 시작합니다. 사용자는 서로 다른 슬롯( Index 2와 3)을 사용하여 Nonce 5에서 두 개의 병렬 트랜잭션(TxA와 TxB)을 성공적으로 제출합니다. 검증자는 이 두 슬롯을 사용됨으로 표시하기 위해 비트맵을 업데이트합니다. 검증자가 TxB를 처리하는 동안 TxA가 완료되었지만 충돌은 발생하지 않습니다.
그러나 사용자가 이미 점유된 Index 2를 재사용하려는 다른 트랜잭션(TxC)을 제출하려고 시도하면 검증자는 이를 중복으로 올바르게 거부합니다. 그런 다음 사용자가 Nonce 6을 사용하여 TxD를 제출하면 시스템은 진행하며, 이로 인해 nonce 업데이트가 트리거됩니다. 현재 Nonce 6으로 증가하고 Bitmap TxD의 Index 에 따라 업데이트됩니다. 이 nonce 증가는 매우 중요한데, 사용자가 현재 유효하지 않은 Nonce 5를 사용하여 TxE를 제출하려고 하면 검증자가 시스템이 진행되어 이전 트랜잭션의 재실행을 차단했기 때문에 이를 거부하기 때문입니다.
분석 및 고려 사항
Nonce Bitmap 방식은 EVM 블록체인에 필수적인 보안 보장과 하위 호환성을 유지하면서도 고빈도 사용자를 괴롭히는 순차성 문제를 직접 해결합니다.
간단
이 설계는 구현하기가 매우 간단합니다. 시스템의 핵심은 직관적인 원칙에 따라 작동합니다. 일반 사용자를 위해 순차적인 Nonce 유지하는 동시에 Bitmap 사용하여 각 단계의 병렬 작업을 추적합니다. Bitmap 확인하고 업데이트하는 비트 조작 로직은 프로세서가 기본적으로 처리하는 효율적인 비트 단위 연산을 사용하여 계산적으로 간단합니다. 전반적인 복잡도는 무작위 논스, Hyperliquid의 접근 방식 또는 2D 논스 관리에 비해 낮습니다.
효율성 및 성능
비트맵 방식은 Hyperliquid의 논스 시스템이나 계정 추상화에 사용되는 2D 논스 관리 방식과 비교했을 때 (동일한 병렬 처리 수준에서) 저장 오버헤드를 64배 절감합니다. 이러한 효율성 덕분에 최소한의 상태 확장(트랜잭션당 1비트)을 유지하면서도 (무제한은 아니지만) 상당한 병렬 처리가 가능합니다. 이 설계는 방대한 64비트 논스 공간을 효과적으로 활용하여 보안을 보장하는 순차적 처리 방식을 손상시키지 않으면서 공간을 분할합니다.
이전 버전과의 호환성
이 접근 방식의 중요한 장점은 원활한 하위 호환성입니다. 대다수 사용자와 애플리케이션의 경우, 이 시스템은 변경 사항이 전혀 필요하지 않습니다. 기존 지갑은 Bitmap 구조 내에서 자동으로 Index 0을 사용하므로 변경 없이 계속 작동합니다. 이 시스템은 기존 애플리케이션의 익숙한 순차적 논스(nonce) 시맨틱을 유지하는 동시에 업그레이드된 지갑의 병렬성을 제공합니다. 이러한 이중 모드 운영은 모든 참여자의 공동 업그레이드 없이도 원활한 생태계 전환을 보장합니다.
하지만 사용자는 eth_getTransactionCount 항상 계정의 총 거래 내역을 반환한다고 가정해서는 안 됩니다. 이 문제는 2D Nonce나 Hyperliquid의 접근 방식에서도 발견됩니다. eth_getTransactionCount 는 주로 PendingNonceAt 함수에 사용됩니다. PendingNonceAt 함수가 재설계됨에 따라 고급 사용자는 이 RPC를 삭제하거나 비활성화할 수 있습니다. 이 eth_getTransactionCount 사용하는 다른 서비스(일반적으로 Explorer)의 경우 로컬 데이터베이스를 사용하여 이 값을 추출할 수 있습니다.
Nonce Bitmap으로 누가 이익을 얻나요?
- 고빈도 트레이더. 복잡한 논스 관리 없이 여러 거래를 동시에 제출하세요. 거래 간 논스 상태 쿼리 필요성을 제거하여 지연 시간을 줄입니다.
- MEV 검색기. 병렬로 처리 가능한 거래 묶음을 전송하여 실행 속도와 성공률을 향상시킵니다.
- DeFi 고급 사용자/고래. 거래 주문이나 거래 중단에 대한 걱정 없이 여러 프로토콜을 포함하는 복잡한 전략을 동시에 실행하세요.
- 개발자. 대량의 거래를 더욱 효율적으로 제출할 수 있는 애플리케이션을 구축하여 사용자 경험을 개선하고 운영상의 복잡성을 줄입니다.
- 일반 사용자. 변경 사항은 없으며, 시스템은 기존 지갑과 하위 호환성을 유지합니다.
다른 접근 방식과의 비교
| 접근하다 | 원래의 | 무작위의 | 하이퍼리퀴드 | 2D 논스 | Nonce 비트맵 |
|---|---|---|---|---|---|
| 주문하기 | 예 | 아니요 | 부분적 | 부분적 | 부분적 |
| 확인 | 단순한 | 단순한 | 더 복잡함(시간 기반과 통합됨) | - 일반 사용자의 경우 원래 접근 방식과 동일 - 고급 사용자에게는 조금 더 복잡함 | - 일반 사용자의 경우 원래 접근 방식과 동일 - 고급 사용자에게는 조금 더 복잡함 |
| 병행 | 아니요 | 네, 무제한입니다 | 네, ~100건의 거래 | 네, nonceKey 의 크기에 따라 다릅니다. | 네, 최대 256개의 거래가 가능합니다. |
| 거래 건수 | 단순한 | 단순한 | 사소하지 않은 | 중간, 필수 API 업데이트 | 사소하지 않은 |
| 지갑 호환성 | 예 | 아니요 | 아니요 | 예, 일반 사용자의 경우 | 예, 일반 사용자의 경우 |
| 추가 저장 공간 | 아니요 | 사용된 모든 nonce를 추적하세요 | 8*100바이트(주소당 사용된 100개의 nonce를 추적) | 8 * 활성 nonceKeys | 주소당 32바이트 |
결론
Nonce Bitmap 접근 방식은 신중한 프로토콜 설계를 통해 다음을 수행할 수 있음을 보여줍니다.
보안이나 호환성을 저해하지 않으면서도 상당한 UX 개선을 달성했습니다. 64비트 nonce 공간이 크게 활용되지 않는다는 점을 확인하여, 계정당 32바이트만 추가하면 256방향 병렬 처리가 가능합니다.
저지연 체인의 경우, 트랜잭션 지연 시간은 더 이상 블록 시간에 의해 제한되지 않습니다. 오히려 사용자가 트랜잭션을 제출하는 속도에 의해 제한됩니다. 다행히 Nonce Bitmap은 이러한 병목 현상을 제거합니다.





