-
Notifications
You must be signed in to change notification settings - Fork 152
Store 상세
이 문서에서는 Libplanet에서 제공하는 IStore
와 IStateStore
인터페이스의 구현체에 대해서 설명합니다.
IStore
인터페이스를 구현하는 구현체들은 반드시 다음의 함수들을 구현합니다. 코드
-
ListChainIds
: 스토어에 저장된 체인 ID들을 반환합니다. -
DeleteChainId
: 스토어에서 체인 ID를 제거합니다. -
GetCanonicalChainId
: Canonical 체인의 ID를 반환합니다. -
SetCanonicalChainId
: 특정 체인 ID를 Canonical 체인으로 설정합니다. -
CountIndex
: 인자로 전달한 체인 ID의 체인에 몇 개의 블록이 있는지 세어 반환합니다. -
IterateIndexes
: 인자로 전달한 체인 ID의 체인의 offset 인덱스의 블록부터 limit 개수의 블록 해시들을 반환합니다. 인덱스가 작은 것 부터 높은 것 순으로 정렬되어 있습니다. -
IndexBlockHash
: 인자로 전달한 체인 ID의 체인의 index 블록의 해시를 반환합니다. -
AppendIndex
: 인자로 전달한 블록해시를 체인 ID의 체인에 붙이고 그 인덱스를 반환합니다. -
ForkBlockIndexes
: 체인을 포크합니다. 사용하지 않는 것을 권장합니다. -
GetTransaction
: TxId에 대응하는 트랜잭션을 스토어에서 찾아 반환합니다. -
PutTransaction
: 트랜잭션을 스토어에 저장합니다. -
IterateBlockHashes
: 체인에 포함 여부와 관계없이 모든 블록들의 해시를 반환합니다. -
GetBlock
: 블록해시에 대응하는 블록을 스토어에서 찾아 반환합니다. -
GetBlockIndex
: 블록해시에 대응하는 블록 인덱스를 스토어에서 찾아 반환합니다. -
GetBlockDigest
: 블록해시에 대응하는 블록 다이제스트를 스토어에서 찾아 반환합니다. 블록 다이제스트는 블록에서 트랜잭션의 내용물을 제거한, 스토리지 저장을 위한 자료 구조입니다. -
PutBlock
: 블록을 스토어에 저장합니다. 내부적으로 블록의 트랜잭션들 역시PutTransaction
메서드를 호출하여 스토어에 별도 Key로 저장합니다. 이미 해당 블록이 스토어에 저장되어 있다면 아무 일도 일어나지 않습니다. -
DeleteBlock
: 블록을 스토어에서 지웁니다. 단순히 스토어에서 지우는 작업만 진행하고 Nonce 등의 정보를 업데이트 하지 않습니다. -
ContainsBlock
: 스토어에 해당 블록이 저장되어있는지 여부를 반환합니다. -
PutTxExecution
:TxExecution
을 스토어에 저장합니다. 중복된 값을 경고 없이 덮어씌웁니다. -
GetTxExecution
: 특정 블록의 트랜잭션의 실행 결과를 반환합니다. 저장된 값이 없다면null
값이 반환됩니다. -
PutTxIdBlockHashIndex
:TxId
의 트랜잭션이 어떤 블록에 포함되어있는지 정보를 저장합니다. -
GetFirstTxIdBlockHashIndex
:TxId
의 트랜잭션이 최초로 포함된 블록의 블록해시 값을 반환합니다. -
IterateTxIdBlockHashIndex
:TxId
의 트랜잭션이 포함된 블록의 블록해시를 모두 반환합니다. -
DeleteTxIdBlockHashIndex
:TxId
이 어떤 블록에 포함되어있는 여부를 기록하는 테이블에서 해당 블록해시를 제거합니다. -
ListTxNonces
: 체인 Id에서 사용하는 논스테이블을 반환합니다. -
GetTxNonce
: 체인 Id의 체인에서 특정Address
의 현재 논스를 반환합니다. 새 트랜잭션을 만들 때 해당 값을 그대로 사용합니다. -
IncreaseTxNonce
: 체인 Id에서 특정Address
의 논스를 주어진 만큼 증가시킵니다. 음수 값을 할당하면 감소시킵니다. -
ContainsTransaction
:TxId
의 트랜잭션이 스토어에 포함되어있는지 여부를 반환합니다. -
CountBlocks
: 체인과 관계없이 스토어에 저장된 모든 블록의 갯수를 반환합니다. -
ForkTxNonces
: 논스 테이블을 포크합니다. 사용하지 않는 것을 권장합니다. -
PruneOutdatedChains
: 현재 Canonical 체인에서 참조하지 않는 체인들을 모두 제거합니다. -
GetChainBlockCommit
: 노드가 수집한 체인 Id의 가장 마지막 블록커밋을 반환합니다. -
PutChainBlockCommit
: 노드가 수집한 체인 Id의 블록 커밋을 저장합니다. -
GetBlockCommit
: 블록에 저장된 커밋을 스토어에서 가져와 반환합니다. -
PutBlockCommit
: 블록커밋을 스토어에 저장합니다. -
DeleteBlockCommit
: 블록커밋 정보를 스토어에서 제거합니다. -
GetBlockCommitHashes
: 스토어에 저장된 모든 블록커밋의 블록해시 값들을 가져옵니다. -
IteratePendingEvidenceIds
,GetPendingEvidence
,GetCommittedEvidence
,PutPendingEvidence
,PutCommittedEvidence
,DeletePendingEvidence
,DeleteCommittedEvidence
,ContainsPendingEvidence
,ContainsCommittedEvidence
: 위 메서드들은 합의 과정 도중 다른 밸리데이터가 위반한 행위들을 스토어에 관리합니다.
Libplanet은 IStore
의 구현체를 몇 가지 제공하지만, 그 중 권장하는 것은 RocksDBStore
입니다. RocksDB는 고성능의 NoSQL Key-Value 스토리지이고, libplanet에서는 최적화를 위해 자주 사용하는 값들에 대한 캐싱을 진행 사용하고 있습니다.
상세 구현은 해당 소스 코드를 참고해주세요.
IStateStore
인터페이스를 구현하는 구현체들은 반드시 다음의 함수들을 구현합니다. 코드
-
GetStateRoot
: 인자로 전달한StateRootHash
에 대응하는 트라이를 반환합니다. -
Commit
: 인자로 전달한 트라이를 스토어에 저장합니다.
트라이의 변경은 ITrie
인터페이스의 메서드들을 이용해 할 수 있습니다. Libplanet은 이 ITrie
를 감싸는 두 자료 구조인 IWorldState
와 IAccountState
를 제공합니다. 액션에서는 이 두 인터페이스 형태로 상태를 관리합니다.
IAction.Execute()
의 인자인 IActionContext
의 IActionContext.PreviousState
는 IWorld
를 반환하고, IWorld
는 Address
를 키로, IAccount
를 값으로 갖는 Dictionary의 자료 구조 형태를 가지고 있습니다. 그리고 IAccount
에서 한 번 더 Address
를 키로 참조하여 실제 상태를 조회하고, 값을 변경할 수 있습니다. 아래 코드는 실제 사용 예시입니다.
public IWorld Execute(IActionContext context)
{
IWorld world = context.PreviousState;
if (Append is { } append)
{
IAccount account = world.GetAccount(ReservedAddresses.LegacyAccount);
string? items = (Text?)account.GetState(append.At);
items = items is null ? append.Item : $"{items},{append.Item}";
account = account.SetState(append.At, (Text)items!);
world = world.SetAccount(ReservedAddresses.LegacyAccount, account);
}
if (Transfer is { } transfer)
{
world = (transfer.From, transfer.To) switch
{
(Address from, Address to) => world.TransferAsset(
context,
sender: from,
recipient: to,
value: FungibleAssetValue.FromRawValue(DumbCurrency, transfer.Amount)),
(null, Address to) => world.MintAsset(
context,
recipient: to,
value: FungibleAssetValue.FromRawValue(DumbCurrency, transfer.Amount)),
(Address from, null) => world.BurnAsset(
context,
owner: from,
value: FungibleAssetValue.FromRawValue(DumbCurrency, transfer.Amount)),
_ => throw new ArgumentException(
$"Both From and To cannot be null for {transfer}"),
};
}
if (Validators is { } validators)
{
world = world.SetValidatorSet(new ValidatorSet(validators.ToList()));
}
return world;
}
ActionEvaluator에서는 액션을 실행할 때 내부적으로 IAction.Execute
를 실행하여 상태를 변경하고, 반환된 IWorld
객체를 ITrie
형태로 다시 변환하여 반환합니다. 그렇게 변경된 ITrie
의 루트 해시와 해당 트리를 스토어에 Commit
하여 상태를 저장합니다.
Libplanet은 IStateStore
의 구현체로서 Merkle-Patricia trie (이하 MPT) 베이스의 TrieStateStore
를 제공하고 있습니다. 내부적으로는 역시 RocksDB 베이스의 RocksDBKeyValueStore
를 사용하며, 자세한 구현은 MPT의 이해가 필요합니다.
MPT는 이더리움에서 상태를 저장하기 위한 자료 구조로서 일부만 변화했을 때 전체가 크게 바뀌지 않는 특징을 가지고 있고, 변화를 추적하기 용이합니다. 보다 자세한 설명은 이더리움 공식 문서 와 구현체를 참고해주세요.