Sui 개발자 치트 시트
Sui Network 개발자를 위한 모범 사례 빠른 참조이다.
Move
General
- Move 개발의 모범 사례는 Code Quality Checklist를 읽는다.
- 일관된 naming과 coding style을 위해 Move 모범 사례을 따른다.
- 최대 크기를 ≤ 1000 item으로 알 수 있는 collection에는
vector기반 collection(vector,VecSet,VecMap,PriorityQueue)을 사용한다.- 제3자 추가를 허용하는 collection, 더 큰 collection, 크기를 알 수 없는 collection에는 dynamic field 기반 collection(
Table,Bag,ObjectBag,ObjectTable,LinkedTable)을 사용한다. - Move object의 최대 크기는 250KB이다. 더 큰 object를 생성하려고 시도하면 transaction이 중단된다. object에 계속 커지는
vector기반 collection이 없도록 한다.
- 제3자 추가를 허용하는 collection, 더 큰 collection, 크기를 알 수 없는 collection에는 dynamic field 기반 collection(
- 함수
f가 호출자로부터 예를 들어 SUI 결제를 받아야 한다면fun f(payment: &mut Coin<SUI>, amount: u64)가 아니라fun f(payment: Coin<SUI>)를 사용한다. 이것이 호출자에게 더 안전한데, 호출자는 자신이 정확히 얼마를 지불하는지 알고f가 올바른 금액을 꺼낼 것이라고 신뢰할 필요가 없기 때문이다.
Composability
- wallet, 앱, explorer에서 object가 표시되는 방식을 사용자 지정하려면 Sui Object Display를 사용한다.
- “self-transfers”를 피한다. 가능하면 현재 함수에서 object를 반환하여 PTB 구성하기에서 설명하는 다른 command에서 사용할 수 있게 한다.
Package upgrades
- package를 게시하기 전에 패키지 업그레이드를 읽는다.
- package는 immutable하므로 게시된 package는 어떤 것이든 영구적으로 호출될 수 있다. 이전 version이 호출되지 않도록 object versioning을 사용한다.
- package
P1을P2로 업그레이드하면P1에 의존하는 다른 package와 client는 계속P1을 사용한다. 이들은P2로 자동 업데이트되지 않는다. 의존 package와 client code 모두P2를 가리키도록 명시적으로 업데이트해야 한다. - 의존 package에 의해 확장되기를 기대하는 package는 모든 version이 준수하는 표준(변하지 않는) interface를 제공하여 각 업그레이드 때 확장을 깨뜨리지 않을 수 있다. Wormhole의 bridge 예제 전반에 걸친 message sending을 참고한다. outbound message를 생성하는 extension package는 Wormhole package의 어떤 version에서든
prepare_message를 사용해MessageTicket을 생성할 수 있고, message를 보내는 client code는 그MessageTicket을 package 최신 version의publish_message에 전달해야 한다.public함수 signature는 삭제하거나 변경할 수 없지만public(friend)함수는 그럴 수 있다. 영구적으로 유지될 library 함수를 노출하는 경우가 아니라면public(friend)또는 private visibility를 적극적으로 사용한다.structtype을 삭제하거나, 그 정의를 변경하거나, 업그레이드를 통해 새 abilities를 추가하는 것은 불가능하다. 새 type은 영구적으로 유지되므로 신중하게 도입한다.
Testing
- multi-transaction, multi-sender test scenario를 흉내 내려면
sui::test_scenariomodule을 사용한다. - 더 나은 test error message를 위해
assert_eq!및assert_ref_eq!macro에는std::unit_testmodule을 사용한다. - black-hole 함수
destroy에는sui::test_utilsmodule을 사용한다. print를 통한 debug printing에는std::debugmodule을 사용한다.- test의 코드 커버리지 정보를 계산하려면
sui move test --coverage를 사용하고, 빨간색으로 강조된 미커버 line을 보려면sui move coverage source --module <name>를 사용한다. 가능하다면 코드 커버리지를 100%까지 끌어올린다.
Apps
- 최적의 성능과 데이터 일관성을 위해 앱은 같은 풀 노드에 write와 read를 제출해야 한다. TS SDK에서 이는 앱이 wallet의
signTransactionBlockAPI를 사용한 뒤 wallet의signAndExecuteTransactionBlockAPI를 사용하는 대신 앱의 풀 노드에서execute_transactionBlock을 호출해 transaction을 제출해야 함을 뜻한다. 이렇게 하면 앱의 풀 노 드에서의 read-after-write-consistency가 보장되어 read가 체크포인트를 기다리는 대신 transaction의 write를 즉시 반영한다. - 앱은 풀 노드에서 과도하게 가져오기보다 자주 읽는 데이터를 위한 로컬 cache를 구현해야 한다.
- 가능하면 새 스마트 계약 코드를 게시하는 대신 programmable transaction block을 사용해 기존 온체인 기능을 조합한다. programmable transaction block은 대규모 batching과 heterogeneous composition을 허용하여 이미 낮은 가스 수수료를 한층 더 낮춘다.
- 앱은 가스 예산, 가스 가격, coin selection을 wallet에 맡겨야 한다. 이렇게 하면 wallet에 더 많은 유연성이 생기고, transaction이 실패하지 않도록 dry run하는 것은 wallet의 책임이 된다.
Signing
- 같은 owned object를 건드리는 두 concurrent transaction에는 절대 서명하지 않는다. 독립적인 owned object를 사용하거나, 다음 transaction을 보내기 전에 한 transaction이 끝날 때까지 기다린다. 이 규칙을 위반하면 client equivocation이 발생할 수 있고, 그러면 두 transaction에 관련된 owned object가 현재 epoch가 끝날 때까지 잠긴다.
- transaction을 만드는 모든
sui clientcommand(예:sui client publish,sui client call)는 서명할 base64 transaction을 출력하기 위해--serialize-outputflag를 받을 수 있다. - Sui는 네이티브 다중 서명(multisig)을 포함하여 transaction 서명을 위한 여러 서명 방식을 지원한다.
zkLogin
- proving service는 가능한 한 드물게 호출한다. 사용자가 실제 transaction을 수행하려고 할 때만 proving service를 호출하도록 앱 flow를 설계한다.
- ephemeral private key를 어떻게 cache하는지 주의한다. private key를 password처럼 매우 민감한 데이터와 비슷하게 취급한다. 만료되지 않은 ephemeral private key와 그에 대응하는 ZK proof가 유출되면 공격자가 사용자의 자산을 훔칠 수 있다.