ERC-2678 스마트 컨트랙트 패키징 표준 v3 (Revised Ethereum Smart Contract Packaging Standard (EthPM v3))

Final · 기타 · 2020-05-26 작성

스마트 컨트랙트의 소스, 컴파일러 설정, 배포 정보를 하나의 JSON 문서(패키지 매니페스트)로 담는 형식을 정의합니다. 도구들이 공통 형식으로 패키지를 만들고 설치하고 검증할 수 있게 합니다.

왜 필요한가

스마트 컨트랙트는 소스 코드, 컴파일러 버전과 설정, 컴파일 결과물, 배포된 주소가 모두 맞아야 재사용하거나 검증할 수 있습니다. 이런 정보를 담는 공통 형식이 없으면 개발 도구마다 제각각의 방식으로 패키지를 기록하게 되고 한 도구로 만든 패키지를 다른 도구에서 쓰기 어렵습니다. 또 같은 내용이라도 저장할 때마다 파일이 조금씩 달라지면 IPFS 같은 콘텐츠 주소 지정(content addressable) 저장소에서 주소가 바뀌어 동일성을 보장할 수 없습니다. 이전 버전 형식은 컴파일러 정보가 컨트랙트마다 중복으로 흩어져 있었고 솔리디티 컴파일러가 내놓는 메타데이터 출력과도 맞지 않아 도구가 다루기 번거로웠습니다. 이 표준은 매니페스트를 컴파일러 출력과 호환되게 고치고 직렬화 규칙을 엄격히 정해, 패키지 관리 도구들이 공통으로 쓸 수 있는 형식을 제공합니다.

심층 설명

직렬화 규칙과 콘텐츠 주소 일관성

매니페스트는 JSON 객체 하나이며 줄바꿈이나 여분의 공백 없이 압축해야 합니다. 모든 객체의 키는 알파벳순으로 정렬해야 하고 같은 객체 안의 중복 키는 무효입니다. 인코딩은 UTF-8이어야 하며 문서 끝에 줄바꿈이 있으면 안 됩니다. 하위 호환을 위해 manifest_version은 최상위 키로 금지됩니다. 이렇게 직렬화를 고정하는 이유는 패키지가 IPFS 같은 콘텐츠 주소 지정 파일시스템에 배포되기 때문입니다. 같은 컨트랙트 자산 집합이 항상 같은 콘텐츠 주소 URI로 해석되도록 보장합니다. 커스텀 필드는 넣을 수 있으나 향후 버전과의 이름 충돌을 피하기 위해 x- 접두사를 붙여야 합니다.

최상위 필드 구성

manifest 필드는 필수이며 값은 ethpm/3이어야 합니다. name은 소문자로 시작하고 소문자, 숫자, 대시만 쓸 수 있으며 정규식 ^[a-z][-a-z0-9]{0,255}$에 맞아야 하고 255자를 넘을 수 없습니다. version은 semver 규칙을 따르는 것이 권장되며 name과 version은 한쪽이 있으면 다른 쪽도 필수입니다. meta에는 authors, license(SPDX 형식 권장), description, keywords, links(website, documentation, repository 키 권장)를 담습니다. 그 외에 sources, contractTypes, compilers, deployments, buildDependencies 필드가 정의되어 있고 모두 선택입니다.

sources와 Source 객체

sources는 이 릴리스의 컨트랙트를 다시 컴파일하는 데 필요한 전체 소스 트리를 담아야 합니다. 각 소스는 content(인라인 소스)나 urls(같은 파일로 해석되는 URL 배열) 중 하나를 반드시 포함합니다. 둘 다 있으면 content가 urls의 파일 내용과 일치해야 합니다. content가 없고 URL에 콘텐츠 해시도 없으면 checksum(algorithm과 hash)이 필수입니다. installPath는 ./로 시작하는 상대 경로여야 하며 소스 폴더 밖 접근을 막기 위해 ../를 포함할 수 없고 모든 소스에서 유일해야 합니다. type은 solidity, vyper, abi-json, solidity-ast-json 중 하나가 권장되고 파일별 license는 패키지 meta의 라이선스보다 우선합니다.

contractTypes와 deployments

컨트랙트 타입 객체는 contractName, sourceId, deploymentBytecode, runtimeBytecode, abi, userdoc, devdoc을 가질 수 있습니다. 패키지는 자기 소스에서 나온 타입만 포함해야 하고 의존성의 타입이나 추상 컨트랙트는 포함하지 않는 것이 규칙입니다. deployments의 키는 BIP122 URI 체인 정의이며 같은 블록체인을 가리키는 중복 키는 허용되지 않습니다. 각 컨트랙트 인스턴스는 contractType과 address가 필수입니다. contractType은 자기 패키지의 별칭이거나 의존성 패키지를 가리키는 <package-name>:<contract-alias> 형식이고 address는 정규식 ^0x[0-9a-fA-F]{40}$에 맞아야 합니다. transaction과 block은 선택이며 인스턴스에 runtimeBytecode가 있으면 타입의 것을 대체합니다.

링크 참조와 링크 값

라이브러리 주소처럼 배포 시점에 채워지는 자리는 링크 참조(Link Reference)로 표시합니다. 링크 참조는 바이트코드 안의 시작 위치 배열 offsets(0부터 셈), 바이트 길이 length, 선택적 name을 가지며 바이트코드 끝을 넘거나 서로 겹치면 무효입니다. 실제로 채워 넣은 값은 linkDependencies의 링크 값(Link Value) 객체로 기록합니다. type이 literal이면 value는 0x 접두사 16진수 바이트이고 reference면 컨트랙트 인스턴스 이름이며 의존성 트리 안의 인스턴스는 <p1>:<p2>:...:<pn>:<contract-instance> 형식으로 가리킵니다. 두 링크 값이 같은 offsets를 공유할 수 없고 각 링크 값은 대응하는 링크 참조가 있어야 합니다. 해석된 값의 길이는 링크 참조의 length와 같아야 합니다.

compilers 배열과 buildDependencies

컴파일러 정보는 최상위 compilers 배열에 둡니다. 각 객체는 name과 version이 필수이고 version은 OS 정보를 빼고 semver 형식 또는 나이틀리 빌드라면 0.4.8-commit.60cc1668 같은 <semver>-<commit-hash> 형식을 따라야 합니다. settings는 컴파일 설정이며 solc라면 공식 컴파일러 입출력 JSON 설명을 따라야 합니다. contractTypes 배열로 어떤 타입이 이 컴파일러로 생성됐는지 밝히는데, runtimeBytecode를 선언한 타입은 어느 컴파일러 객체에든 귀속되어야 하고 한 타입이 둘 이상의 컴파일러에 귀속될 수는 없습니다. buildDependencies는 의존 패키지 목록으로, 키는 유효한 패키지 이름이고 값은 같은 매니페스트 버전의 패키지로 해석되는 콘텐츠 주소 URI여야 합니다.

v2에서 바뀐 점과 하위 호환

v3는 매니페스트 스키마를 컴파일러의 메타데이터 출력과 호환되게 바꾸고, sources 정의를 넓혀 더 다양한 소스 파일 형식을 담고 컴파일러의 JSON 입력으로 쓸 수 있게 했습니다. 컴파일러 정의를 최상위 compilers 배열로 옮겨 컴파일러 버전, 소스, 결과물 사이의 연결을 단순화하고 중복 정보를 없앴으며 키 표기를 snake_case에서 camelCase로 통일했습니다. 버전 식별 필드는 manifest_version에서 manifest로 바뀌었고 v3 패키지는 반드시 최상위에 manifest: ethpm/3을 정의해야 하며 manifest_version 키는 금지됩니다. 체인 식별에는 v1부터 쓰던 BIP122 URI 방식을 그대로 사용합니다. 이 제안은 Final 상태로 확정된 표준입니다.

쓸 때 주의할 점

ERC 원문 · ← ERCs