Skip to main content

Impact VM

info

Impact은 아직 활발히 수정 중입니다. 스토리지 관련 비용을 포함한 여러 속성이 변경될 수 있습니다.

현재 사용자가 Impact을 직접 작성할 수는 없으며, 이 기능은 향후 추가될 수 있습니다.

프로그램의 온체인 부분은 온체인 VM 언어인 Impact으로 작성됩니다. 컨트랙트를 작성할 때 Impact의 세부 사항까지 알 필요는 없지만, 트랜잭션과 컨트랙트 출력을 검사할 때 접하게 될 수 있습니다.

Impact은 스택 기반의 비튜링 완전 상태 조작 언어입니다. 컨트랙트는 다음 세 가지를 포함하는 스택에서 실행됩니다:

  • 해당 트랜잭션에 관한 컨텍스트를 기술하는 'context' 객체
  • 실행 중 컨트랙트가 수행한 작업을 수집하는 'effects' 객체
  • 컨트랙트의 현재 상태.

프로그램 실행은 선형으로 진행되며, 어떤 연산도 프로그램 카운터를 감소시킬 수 없고, 모든 연산의 소요 시간은 제한됩니다. 프로그램 실행에는 'gas' 한도로 제한할 수 있는 비용이 부과됩니다. 프로그램은 중단하여 트랜잭션의 해당 부분을 무효화하거나, 성공하여 시작 시와 같은 형태의 스택을 남겨야 합니다. 결과 effects는 transcript에 선언된 effects와 일치해야 하며, 컨트랙트 상태가 저장 가능으로 표시된 경우에만 갱신된 상태가 채택됩니다.

Transcripts

실행 transcript는 다음으로 구성됩니다:

  • 이 호출의 수수료를 산출하는 데 사용되는 선언된 gas 한도
  • 컨트랙트의 시맨틱스를 다른 부분의 것과 바인딩하는 데 사용되는 선언된 effects 객체
  • 실행할 프로그램.

Values

Impact 스택 머신은 다음 상태 값을 다룹니다:

  • null
  • <x: y>, 필드 정렬 이진 셀
  • Map { k1: v1, k2: v2, ... }, 필드 정렬 이진 값에서 상태 값으로의 맵
  • Array(n) [ v0, v1, ... ], 0 < n < 16개의 상태 값 배열
  • MerkleTree(d) { k0: v1, k2: v2, ... }, 희소 고정 깊이 1 <= d <= 32 Merkle 트리, 슬롯 k0, k2, ...에 리프 해시 v1, v2, ... 포함 (일반적으로 16진수 문자열로 표현됨).

Field-aligned binary

Impact에서 사용되는 기본 데이터 유형은 FAB(Field-Aligned Binary) 값입니다. 이 값은 모든 소수 필드에서 필드 요소로 인코딩하는 데 필요한 정보를 유지하면서 복잡한 데이터 구조를 이진 표현으로 저장할 수 있습니다.

정렬된 값은 정렬된 atom의 시퀀스로 구성되며, 각 atom은 바이트 문자열과 정렬 atom으로 이루어집니다. 정렬 atom은 다음 중 하나입니다:

  • f, 필드 정렬을 나타냄: atom이 필드 요소의 리틀 엔디안 표현으로 해석됩니다.
  • c, 압축 정렬을 나타냄: atom이 값을 해싱하여 도출된 필드 요소로 해석됩니다.
  • bn, n-바이트 정렬을 나타냄: atom이 n 바이트를 압축적으로 인코딩하기 위해 소수 필드와 곡선에 따라 필드 요소의 시퀀스로 해석됩니다.

Programs

프로그램은 연산의 시퀀스로, opcode 뒤에 해당 opcode에 따른 여러 인수가 뒤따릅니다. 프로그램은 평가 모드와 검증 모드, 두 가지로 실행할 수 있습니다. 검증 모드에서는 popeq[c] 인수에 대해 동등성이 강제되고, 평가 모드에서는 결과가 수집됩니다.

Op은 스택에 대해 고정된 효과를 가지며, -{a, b} +{c, d}로 표기합니다. 스택 맨 위의 항목 ab를 소비하고(ab 위에 위치), cd로 대체합니다(dc 위에 위치). 여기서 값의 수는 예시일 뿐입니다. 상태 값은 프로그램 관점에서 _불변_입니다. 스택의 값을 직접 변경할 수는 없지만, 수정된 버전으로 대체할 수 있습니다. [a]는 셀 a에 저장된 값을 참조합니다. 편의상 '[a] := ...를 설정'을 '...를 포함하는 새 셀 a를 생성'으로 축약합니다. 출력 값에 '를 접두사로 붙이면 메모리에만 유지되고 디스크에 기록되지 않는 약한 값임을 나타내며, 입력 값에 '를 접두사로 붙이면 약한 값일 수 있음을 나타냅니다. "는 입력이 약한 값일 수 있음을 나타내고, 그런 경우에만 해당 표시가 달린 출력도 약한 값이 됩니다.

인수가 사용되는 경우, State는 상태 값, u21은 21비트 부호 없는 정수, path(n)는 FAB 값 또는 기호 stack의 시퀀스를 나타내며, 인덱싱 키를 직접 지정하거나 스택 값을 대신 사용할지를 표시합니다.

이름Opcode스택인수비용 (비스케일)설명
noop00-{} +{}n: u21n아무 것도 하지 않음
lt01-{'a, 'b} +{c}-1[c] := [a] < [b] 설정
eq02-{'a, 'b} +{c}-1[c] := [a] == [b] 설정
type03-{'a} +{b}-1[b] := typeof(a) 설정
size04-{'a} +{b}-1[b] := size(a) 설정
new05-{'a} +{b}-1[b] := new [a] 설정
and06-{'a, 'b} +{c}-1[c] := [a] & [b] 설정
or07-{'a, 'b} +{c}-1`[c] := [a]
neg08-{'a} +{b}-1[b] := ![a] 설정
log09-{'a} +{}-1a를 이벤트로 출력
root0a-{'a} +{b}-1[b] := root(a) 설정
pop0b-{'a} +{}-1a 제거
popeq0c-{'a} +{}a: State 검증 시에만`a
popeqc0d-{'a} +{}a: State 검증 시에만`a
addi0e-{'a} +{b}c: State1[b] := [a] + c 설정, 덧셈은 아래 정의
subi0f-{'a} +{b}c: State1[b] := [a] - c 설정, 뺄셈은 아래 정의
push10-{} +{'a}a: State`a
pushs11-{} +{a}a: State`a
branch12-{'a} +{}n: u211a가 비어 있지 않으면, n개의 연산 건너뜀.
jmp13-{} +{}n: u211n개의 연산 건너뜀.
add14-{'a, 'b} +{c}-1[c] := [a] + [b] 설정
sub15-{'a, 'b} +{c}-1[c] := [b] - [a] 설정
concat16-{'a, 'b} +{c}n: u211`
concatc17-{'a, 'b} +{c}n: u211concat과 동일하지만, ab가 이미 메모리에 있어야 함
member18-{'a, 'b} +{c}-size(b)[c] := has_key(b, a) 설정
rem19-{a, "b} +{"c}-size(b)c := rem(b, a, false) 설정
remc1a-{a, "b} +{"c}-size(b)c := rem(b, a, true) 설정
dup3n-{x*, "a} +{"a, x*, "a}-1a를 복제, x*n개의 스택 항목
swap4n-{"a, x*, †b} +{†b, x*, "a}-1두 스택 항목 교환, x* n개 항목이 사이에 있음
idx5n-{k*, "a} +{"b}c: path(n)`c
idxc6n-{k*, "a} +{"b}c: path(n)`c
idxp7n-{k*, "a} +{"b, pth*}c: path(n)`c
idxpc8n-{k*, "a} +{"b, pth*}c: path(n)`c
ins9n-{"a, pth*} +{†b}-sum size(x_i)pth*{key_{n+1}, x_{n+1}, ..., key_1, x_1}, x'_{n+2} = a, x'_j = ins(x_j, key_j, cached, x'_{j+1}), b = x'_1 설정. ax_j의 가장 약한 수정자이며, cachedfalse
inscan-{"a, pth*} +{†b}-sum size(x_i)ins와 동일하지만, cachedtrue
ckptff-{} +{}1내부적으로 원자적인 프로그램 세그먼트 사이의 경계를 표시. 점프로 넘어서는 안 됨.

위 설명에서 다음과 같은 축약 표기를 사용합니다. 별도로 지정하지 않은 경우, 결과 값은 Cell에 배치되고 FAB 값으로 인코딩됩니다.

  • a + b, a - b, 또는 a < b (총칭 a op b), 셀 ab의 내용에 op를 적용, 64비트 부호 없는 정수로 해석, 정렬 b8.
  • a ++ bab의 필드 정렬 이진 연결.
  • a == b는 두 셀의 동등성 확인, 적어도 하나는 최대 64바이트의 데이터를 포함해야 함
  • a & b, a | b, !a는 셀 a와 (가능하면) b의 내용에 대해 불리안 and, or, not으로 처리. 이들은 1 또는 0을 인코딩해야 함.
  • typeof(a)는 상태 값의 유형을 나타내는 태그를 반환:
    • <a: b>: 0
    • null: 1
    • Map { ... }: 2
    • Array(n) { ... }: 3 + n * 32
    • MerkleTree(n) { ... }: 4 + n * 32
  • size(a)Map의 비null 항목 수, Array(n) 또는 MerkleTree(n)n을 반환.
  • has_key(a, b)bMap a의 비null 값에 대한 키이면 true를 반환.
  • new ty는 태그 ty(typeof가 반환하는 것과 같은)에 따라 상태 값의 새 인스턴스를 생성:
    • cell: 빈 값 포함.
    • null 자체
    • Map: 빈 맵
    • Array(n): n개의 null 배열
    • MerkleTree(n): 빈 Merkle 트리
  • a.get(b, cached)b로 인덱싱된 하위 항목을 검색. 하위 항목이 메모리에 로드되어 있지 않고, cachedtrue이면, 이 명령은 실패. 다른 a의 경우:
    • a: Map, 키 b에 저장된 값
    • a: Array(n), 인덱스 b < n의 값
  • rem(a, b, cached)a에서 (get에서와 같이) b로 인덱싱된 하위 항목을 제거. 하위 항목이 메모리에 로드되어 있지 않고, cachedtrue이면, 이 명령은 실패.
  • ins(a, b, cached, c)c를 인덱스 c에서 a에 하위 항목으로 삽입. 이 인덱스의 경로가 메모리에 로드되어 있지 않고, cachedtrue이면, 이 명령은 실패.
  • root(a)MerkleTree(n) a의 Merkle 트리 루트를 출력.

Context and effects

context는 다음 항목을 순서대로 포함하는 Array(_)입니다:

caution

현재 이 중 처음 두 항목만 올바르게 초기화됩니다!

  1. 현재 컨트랙트의 256비트 정렬 주소를 포함하는 Cell.
  2. CoinCommitment 키에서 64비트 정렬 Merkle 트리 인덱스로의 Map (새로 할당된 모든 코인용).
  3. 블록의 UNIX 에포크 이후 초 단위 64비트 정렬 근사값을 포함하는 Cell.
  4. 실제 값이 벗어날 수 있는 최대 범위를 나타내는 블록의 32비트 정렬 초를 포함하는 Cell.
  5. 블록의 256비트 해시를 포함하는 Cell.

이 목록은 향후 마이너 버전 업데이트에서 확장될 수 있습니다.

effects는 다음 항목을 순서대로 포함하는 Array(_)입니다:

  1. Nullifier에서 null로의 Map (claim된 nullifier 집합).
  2. CoinCommitment에서 null로의 Map (claim된 수신 코인 집합).
  3. CoinCommitment에서 null로의 Map (claim된 소비 코인 집합).
  4. (Address, Bytes(32), Field)에서 null로의 Map (claim된 컨트랙트 호출).
  5. Bytes(32)에서 u64 셀로의 Map (모든 특수화 해시에 대해 발행된 코인).

이 목록은 향후 마이너 버전 업데이트에서 확장될 수 있습니다.

effects[{}, {}, {}, {}, {}]로 초기화됩니다.

contexteffects는 모두 캐시된 것으로 간주됩니다. 소수의 opcode만으로 데이터를 컨트랙트 상태에 저렴하게 복사하는 것을 방지하기 위해, 둘 다 약한 값으로 플래그가 지정되며 이들을 사용한 모든 연산 결과도 마찬가지입니다. 최종 state'가 오염되면 트랜잭션이 실패하여, 이런 데이터가 컨트랙트 상태에 직접 복사되는 것을 방지합니다.