정책 인식 프리컴파일

mechanism privacy

정책 인식 프리컴파일은 PCL 프록시 없이 자체 ContractPolicyConfig를 직접 보유하며, 정책 세트가 비어서는 안 되고 삭제할 수도 없습니다.

대부분의 컨트랙트 범위 PCL 강제는 PCL 래핑 프록시를 통해 수행됩니다. 프록시의 preCall/postCall 훅이 프록시 주소에 바인딩된 ContractPolicyConfig를 평가하는 방식입니다. 정책 인식 프리컴파일은 이와 다릅니다. 바이너리가 지원하는 프리컴파일로, 자체 프리컴파일 경계에서 코드가 PCL 정책을 직접 평가합니다. 현재 정책 인식 프리컴파일은 0x100000000000000000000000000000000000000b의 Privacy 프리컴파일 하나입니다. 프리컴파일은 배포된 컨트랙트가 아니므로 PCL 프록시로 등록할 수 없고, 프록시 훅 경로를 거치지도 않습니다. 대신 프리컴파일 주소를 IPcl.changeContractPoliciesContractPolicyConfig에 직접 바인딩하며, 프리컴파일이 상태 변경 호출마다 그 설정을 읽습니다.

아키텍처

flowchart LR
  U["User / dApp"]:::evm
  PRIVACY["Privacy precompile<br/>0x…000b"]:::precompile
  PCL["PCL precompile<br/>0x…0005"]:::precompile
  CFG["ContractPolicyConfig<br/>keyed by 0x…000b"]:::precompile
  STATE["Shielded state"]:::precompile

  U -->|"deposit / transfer / withdraw"| PRIVACY
  PRIVACY -->|"read policies"| PCL
  PCL --> CFG
  PRIVACY -->|"apply if all rules pass"| STATE

  classDef evm fill:#0096AA,stroke:#0096AA,color:#fff;
  classDef precompile fill:#FF8C50,stroke:#FF8C50,color:#fff;

Privacy 프리컴파일은 상태를 변경하는 호출마다 PCL에서 자신의 ContractPolicyConfig를 읽습니다. 프록시 홉이 없습니다.

무엇이 프리컴파일을 정책 인식으로 만드는가

두 가지입니다. 첫째, 체인 바이너리가 해당 프리컴파일 주소를 정책 인식 대상으로 명시적으로 등록해 둡니다. 둘째, 프리컴파일 자체 코드가 호출 시점에 자신의 ContractPolicyConfig를 읽고 상태를 변경하기 전에 규칙을 평가합니다. 현재 릴리스에서 유일한 정책 인식 프리컴파일은 Privacy 프리컴파일입니다. 상태를 변경하는 모든 privacy 호출(deposit, transfer, withdraw와 각각의 WithAuthorization 변형, 두 종류의 batch 변형)은 이 경계에서 PCL 정책 평가를 통과합니다.

PCL 프록시와 다른 등록 규칙

ContractPolicyConfig 진입점(IPcl.changeContractPolicies)은 정책 인식 프리컴파일 주소를 _contract로 받습니다. 프리컴파일에 대해서는 deployPclProxy를 호출하지 않으며, 정책 인식 프리컴파일을 PCL 프록시로 등록하려는 시도는 체인 계층에서 거절됩니다. 일반 PCL 프록시에는 적용되지 않는 두 가지 규칙이 추가로 적용됩니다.

  • policies 배열은 반드시 비어 있지 않아야 합니다. policies: []로 제출하면 CannotEmpty("policy-aware precompile policies")로 revert됩니다.
  • 정책 인식 프리컴파일 주소에 대해 removeContractPolicies를 호출하면 동일한 CannotEmpty 오류로 revert됩니다. 정책을 바꾸는 유일한 방법은 changeContractPolicies로 비어 있지 않은 대체 세트를 제출하는 것입니다.


정책 인식 프리컴파일은 항상 호출 경로에 있기 때문에 이런 규칙이 존재합니다. 정책이 없는 상태로 두면 체인이 항상 평가한다고 가정하는 강제 지점이 조용히 비활성화됩니다.
// Privacy 프리컴파일에 규칙을 바인딩합니다. 최초 호출에서는 페이로드의
// `admin`이 이후 게이트키퍼가 되고, 이후 호출은 그 admin에서 와야 합니다.
const PCL     = "0x1000000000000000000000000000000000000005";
const PRIVACY = "0x100000000000000000000000000000000000000b";

await wallet.writeContract({
  address: PCL,
  abi: pclAbi,
  functionName: "changeContractPolicies",
  args: [{
    _contract: PRIVACY,
    admin:     privacyAdmin,          // TODO: 실제 admin으로 교체
    policies:  [nonEmptyPolicySet],   // 비어 있지 않아야 합니다
  }],
});

admin 권한은 체인 전역 policy admin과 분리됩니다

정책 인식 프리컴파일의 ContractPolicyConfig에 저장된 admin 필드가 그 설정을 변경할 수 있는 유일한 게이트키퍼입니다. IPcl.policyAdmin()이 반환하는 체인 전역 policyAdmin은 여기서 자동 권한을 가지지 않습니다. 저장된 현재 컨트랙트 admin(최초에 설정을 제출한 호출자)만이 admin을 회전하거나 정책 세트를 교체할 수 있으며, 두 작업은 하나의 changeContractPolicies 호출에서 원자적으로 이뤄집니다.

전역 정책도 함께 적용됩니다

정책 인식 프리컴파일의 컨트랙트 범위 ContractPolicyConfig는 체인 전역 GlobalPolicyConfig에 더해 실행됩니다. 프리컴파일에 대한 모든 호출은 다른 트랜잭션과 동일한 방식으로 전역 정책 평가를 먼저 통과하고, 그다음 프리컴파일이 자신의 컨트랙트 범위 정책을 평가합니다. 어느 범위든 독립적으로 호출을 거절할 수 있습니다.

왜 프록시가 아니라 프리컴파일 경계인가

Privacy 프리컴파일은 예치, 노트 소비 전송, 인출 등 shielded 값 흐름을 처리하며 입력 형식이 일반 Solidity 호출이 아닙니다. 이를 프록시로 래핑하면 hot-path 작업에 매번 추가 홉을 강제하거나, 프록시를 우회하는 호출에서 규칙이 조용히 우회되는 결과를 낳습니다. 프리컴파일 경계에 정책을 바인딩하면 강제를 우회할 방법이 없습니다. Shielded 상태에 도달하려면 정책을 평가하는 동일한 프리컴파일을 반드시 거쳐야 하기 때문입니다.
ESC
검색어를 입력하세요