-
Notifications
You must be signed in to change notification settings - Fork 153
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는 이더리움에서 상태를 저장하기 위한 자료 구조로서 일부만 변화했을 때 전체가 크게 바뀌지 않는 특징을 가지고 있고, 변화를 추적하기 용이합니다. 보다 자세한 설명은 이더리움 공식 문서 와 구현체를 참고해주세요.