ZooBC 위키
데이터와 저장소

분산 저장소 풀

분산 저장소는 트랜잭션에 담기에는 너무 큰 파일을 보관합니다. 체인은 각 파일의 매니페스트와 예치금만 기록하고, 조각들은 모든 노드가 재현할 수 있는 추첨으로 배치된 등록 노드들에 각각 다섯 개의 사본으로 보관됩니다. 파일의 임대료는 에포크마다 바이트를 여전히 가지고 있음을 증명하는 보유자들에게 지급됩니다.

조각, 루트, 매니페스트

저장된 파일은 1 MiB(1,048,576바이트)의 조각으로 잘립니다. 각 조각은 SHA3-256 해시로 이름이 붙으며, 파일의 신원인 루트는 조각 크기, 전체 크기, 조각 id 목록에 대한 해시입니다.

piece id = SHA3-256(piece)
root     = SHA3-256(piece size (u32) ‖ total size (u64) ‖ piece ids)

조각은 통째로 복사됩니다. ZooBC는 소거 부호를 쓰지 않습니다. StoreFile 트랜잭션(유형 40)이 매니페스트를 체인에 고정합니다. 루트, 전체 크기, 조각 크기, 최소 0.01 ZBC의 예치금, 1~100,000개의 조각 id, 그리고 선택적인 접근 블록입니다. 조각 자체는 결코 체인에 올라가지 않습니다. 이미 활성 상태인 루트에 대한 StoreFile은 수수료를 내는 무동작이며, 정리된 루트는 다시 저장할 수 있습니다.

업로드하려면 지갑이 파일을 노드의 POST /api/v1/storage/upload로 보내며, 노드는 StoreFile에 쓸 루트, 크기, 조각 id를 돌려줍니다. 노드는 저장 기능이 꺼져 있을 때(503), 본문이 비어 있을 때(400), 남은 공간이 2 GiB 미만이거나 아직 고정되지 않은 조각이 256 MiB를 넘을 때(507), 클라이언트가 600초에 업로드 10회나 시간당 32 MiB를 넘을 때(429) 거부합니다.

파일이 1 MiB 조각으로 잘리고, 매니페스트는 체인에 올라가며, 각 조각은 노드 다섯 개로 갑니다.
파일이 1 MiB 조각으로 잘리고, 매니페스트는 체인에 올라가며, 각 조각은 노드 다섯 개로 갑니다.

누가 조각을 보관하는가

배치에는 랑데부 해싱을 씁니다. mainnet에서 시간은 240블록, 약 1시간의 저장 에포크로 나뉩니다. 한 에포크의 한 조각에 대해 모든 활성 등록 노드가 가중치를 받습니다.

weight = SHA3-256(piece id ‖ node public key ‖ epoch seed)

에포크 시드는 에포크를 여는 블록, 즉 높이 에포크 × 240인 블록의 해시입니다. 가중치가 가장 높은 노드 다섯 개가 예상 보유자이며, 다섯은 체인 파라미터 storage_replication입니다. 노드가 다섯 개보다 적으면 모든 노드가 조각을 보관합니다. 공식의 모든 것이 체인 데이터이므로, 모든 노드가 아무 공지 없이 같은 다섯 개를 계산합니다. 보유자에게 지급하는 집계는 이전 블록 시점의 레지스트리를 읽으므로, 두 노드가 그 집합에 대해 의견이 갈리는 일은 없습니다.

보유자는 에포크마다 바뀌며, 인계 기간은 서로 겹칩니다. 노드는 에포크마다 자신에게 배정된 조각을 먼저 현재 보유자들에게서, 그다음 이전 보유자들에게서, 그다음 아무 노드에게서나 가져옵니다. 밀려 들어온 조각은 해시가 일치하고 자신이 이번 에포크나 이전 에포크의 예상 보유자일 때만 받아들입니다. 배정되지 않은 조각은 이전 에포크에도 보유자가 아니었고 파일이 최소 1시간 이상 된 경우에만 삭제합니다.

저장은 기본으로 켜져 있습니다. 아카이브의 청크를 보관하는 것과 마찬가지로, 조각을 보관하는 것은 등록 노드 좌석의 의무입니다. 운영자는 node.conf에서 저장을 끌 수 있으며([storage] enabled = false), 그러면 저장 보상만 잃습니다. 이 스위치는 체인이 볼 수 없는 로컬 설정이므로 추첨은 이를 참고하지 않습니다. 저장을 끈 노드도 다른 노드와 똑같이 추첨되지만, 결코 증명하지 않으므로 그 조각에 대해 아무것도 받지 못하고 점수도 잃지 않으며, 그 조각은 작동하는 사본이 하나 줄어듭니다. 복제 수와 에포크 길이는 node.conf에 무엇이 적혀 있든 언제나 체인의 파라미터에서 가져옵니다.

저장 증명

체인은 조각을 결코 보지 않으므로 혼자서는 보유자를 검사할 수 없습니다. 대신 에포크마다 각 보유자는 바이트를 가진 사람만 계산할 수 있는 챌린지에 답합니다.

challenge = SHA3-256(epoch seed ‖ piece id ‖ epoch (u64 LE))
proof     = SHA3-256(piece bytes ‖ challenge)

에포크가 시작되기 전에는 아무도 챌린지를 알 수 없습니다. 보유자들은 SubmitStorageProof 트랜잭션(유형 41)으로 답을 보냅니다. 이는 등록 노드의 키로 서명하는 수수료 없는 의무이며, 트랜잭션 하나가 한 노드의 그 에포크 배치 전체를 담습니다.

에포크 경계마다 체인은 답들을 비교합니다. 가장 많은 서로 다른 노드가 제출한 값을 진실로 받아들이되, 다른 값이 그것과 동수가 아니어야 하며, 최소 세 보유자가 동의할 때만(oracle_quorum) 인정합니다. 그러면 동의한 각 보유자의 소유자에게 스토리지 풀에서 지급합니다.

reward = the active files' rent for one epoch ÷ the expected proofs (pieces × 5)
paid   = min(reward, storage pool balance)

다수 의견에 밀린 보유자는 그 에포크에 아무것도 벌지 못하지만 참여 점수는 잃지 않습니다. 체인은 바이트를 결코 가지고 있지 않으므로, 판단할 수 있는 것은 보유자들 사이의 합의뿐이기 때문입니다. 아무것도 보내지 않은 보유자는 감사 테이블에 기록됩니다. 아직 성숙하지 않은 노드는 아무것도 벌지 못하며, 그 저장 보상은 풀에 남습니다(성숙과 수입).

보유자들은 에포크마다 새 챌린지에 답합니다. 최소 셋이 동의하고 동수인 답이 없으면, 동의한 각 보유자가 지급받습니다.
보유자들은 에포크마다 새 챌린지에 답합니다. 최소 셋이 동의하고 동수인 답이 없으면, 동의한 각 보유자가 지급받습니다.

임대료

mainnet에서 기간인 172,800블록(약 30일)마다 한 번, 체인은 파일의 예치금에서 한 기간의 임대료를 스토리지 풀(ZBCSTORE)로 옮깁니다.

rent = max(1, ceil(size ÷ 1,048,576)) × price per MiB

가격은 데이터셋과 같으며, 시작 시 MiB당 0.05 ZBC입니다. 임대료는 최소 1 MiB 이상, 메비바이트 단위로 부과됩니다. 42바이트 파일은 기간당 0.05 ZBC를 내고, 1 MiB보다 1바이트 큰 1,048,577바이트 파일은 0.1 ZBC를 냅니다. 노드의 GET /api/v1/storage/quote?bytes=&blocks=는 같은 공식으로 예치금의 가격을 계산해 줍니다.

어떤 계정이든 FundStoredFile(유형 296)로 활성 파일의 예치금에 돈을 더할 수 있으며, 한 번에 최소 0.01 ZBC입니다. 예치금으로 한 기간 전체를 감당할 수 없게 되면 파일은 정리됩니다. 그 기록은 저장되지 않음으로 표시되고, 나머지는 롱제비티 풀로 갑니다.

비공개 파일

StoreFile의 접근 블록은 파일을 비공개로 표시하고(플래그 비트 0), 1~16개 주소의 허용 목록을 추가할 수 있습니다(플래그 비트 1). 그러면 노드의 API는 내용에 대한 서명 없는 요청을 거부하고(401), 소유자나 목록에 없는 사람의 서명된 요청도 거부합니다(403). 비공개 파일은 공개 목록에서 빠지며, 활성 비공개 파일과 조각을 공유하는 공개 파일도 같은 방식으로 보호됩니다.

"비공개"는 암호화가 아니라 접근 방식입니다. 조각은 여전히 암호화되지 않은 채 보유자들에게 복사되고, 노드들은 서로 조각을 제공하므로, 보유 노드의 운영자는 자기 디스크의 바이트를 읽을 수 있습니다. 내용이 중요하다면 업로드하기 전에 암호화하십시오. 그러면 사용자의 키가 내용을 보호하고, 비공개 플래그는 그보다 가벼운 두 번째 보호막이 됩니다.

같이 보기