의도 중심 프로그래밍에 대한 첫 번째 살펴보기 ft. Pint

이 기사는 기계로 번역되었습니다
원문 표시

저자: Figo, 아이오에스지 벤처스(IOSG Ventures)

명령형 프로그래밍 대 선언형 프로그래밍: 패러다임 의 변화

블록체인 세계에서 프로그래밍 패러다임은 개발자가 기술과 상호작용하는 방식과 사용자가 결과를 경험하는 방식을 정의합니다. 전통적인 필수적 접근 방식과 새롭게 등장한 선언적 접근 방식의 주요 차이점을 공감할 수 있는 비유를 사용하여 분석해 보겠습니다. 좋아하는 카페에서 맞춤형 커피를 주문하는 것입니다.

명령형 프로그래밍: 레시피 따르기

카페에 들어가서 바리스타에게 커피를 만드는 자세한 단계 목록을 준다고 상상해보세요. "콩 20g을 갈아서 90°C의 물 200ml를 넣고 4분간 끓인 후, 세라믹 머그잔에 붓습니다." 여러분은 원하는 커피를 얻기 위해 모든 단계를 정확하게 따르도록 프로세스를 세세하게 관리하고 있습니다.

이것이 블록체인에서 명령형 프로그래밍이 작동하는 방식입니다. 개발자는 데이터 가져오기부터 거래 실행까지 프로세스의 모든 단계를 지시하는 스마트 계약을 작성합니다. 이렇게 하면 프로세스가 의도한 대로 수행되도록 보장할 수 있지만, 특히 예상치 못한 상황이 발생하면 엄격하고 비효율적일 수 있습니다.

선언적 프로그래밍: 결과 정의

이제 같은 카페에 들어가서 "중간 정도의 강한 커피, 설탕 없음, 세라믹 머그잔에 주세요."라고 말한다고 상상해보세요. 바리스타는 당신이 무엇을 원하는지 알고 있으며, 다른 양조 방법을 사용하거나 사용 가능한 원두에 따라 분쇄 크기를 조정하는 등 그것을 만드는 가장 좋은 방법을 선택할 수 있습니다.

이것이 선언적 프로그래밍의 본질입니다. 모든 단계를 지정하는 대신 원하는 결과를 정의하면 시스템이 이를 달성하는 가장 좋은 방법을 알아냅니다. 이 접근 방식은 더 유연하여 현재 조건과 사용자 선호도에 따라 조정할 수 있습니다.

주요 차이점을 강조한 표는 다음과 같습니다.

출처 : Figo, IOSG

블록체인 애플리케이션에 Intents가 필요한 이유는?

의도 이해

기존 블록체인 설정에서는 특정 상태 변경을 달성하기 위한 단계별 지침을 제공해야 합니다. 하지만 최종 목표만 지정하고 시스템이 거기에 도달하는 가장 좋은 방법을 알아내도록 할 수 있다면 어떨까요? 이것이 블록체인의 의도에 대한 아이디어입니다. 사용자가 원하는 것을 선언하면 시스템이 나머지를 처리합니다.

예를 들어, 블록체인에 "최고의 가격으로 1 이더리움(ETH) 판매"하라고 말하는 대신, 사용자는 "내 1 이더리움(ETH) 와 교환하여 최소 2500 테더 USDT(USDT) 얻겠다"는 의도를 선언할 수 있습니다. 그러면 시스템은 잠재적으로 여러 거래소 또는 유동성 풀에서 이 요청을 충족하는 가장 좋은 방법을 찾습니다.

필수 블록체인의 과제

명령형 프로그래밍의 경직성은 종종 여러 가지 문제를 야기합니다.

  • 불확실한 결과: 사용자는 거래가 확인될 때까지 거래 결과를 알 수 없는 경우가 많아 스트레스가 많고 위험할 수 있습니다.
  • 시장 비효율성: DeFi 거래와 같이 특정 결과에 대한 수요가 높을 때 필수 실행은 병목 현상이 발생할 수 있습니다.
  • 보안 위험: 단계가 더 자세해지면 실패 가능성이 더 커지고 버그와 악용의 위험도 커집니다.
출처 : Essential Docs

이러한 문제는 특히 DeFi와 같은 환경에서 흔히 발생하는데, 사용자는 거래 실패, 높은 슬리피지, MEV(Miner Extractable Value) 노출과 같은 문제에 직면하게 됩니다.

선언적 블록체인의 부상

Essential과 같은 선언적 블록체인은 프로세스보다는 결과에 초점을 맞추어 이러한 문제를 해결하고자 합니다. 최종 상태가 무엇이어야 하는지 정의하고 의도를 사용하여 이를 달성함으로써 이러한 시스템은 여러 가지 이점을 제공합니다.

  • 예측 가능한 결과: 사용자는 블록체인이 원하는 결과를 제공할 것이라고 신뢰할 수 있습니다.
  • 보안 강화: 단계가 적으면 문제가 발생할 가능성도 줄어듭니다.
  • 확장성: 결과를 최적화함으로써 선언적 블록체인은 상당히 많은 컴퓨팅 리소스를 요구하지 않고도 더 복잡한 작업을 처리할 수 있습니다.

의도 중심 언어

블록체인 공간에서 의도 중심 프로그래밍이 인기를 얻으면서 Pint (Essential에서 개발) 및 Juvix (Anoma에서 개발)와 같은 언어가 등장하여 개발자가 특정 단계가 아닌 결과에 집중할 수 있도록 돕습니다. 이러한 언어는 블록체인 개발에 접근하는 새로운 방식을 제공하며, 거기에 도달하기 위한 절차적 지침보다 시스템의 원하는 상태를 우선시합니다.

이 섹션에서는 Essential의 선언적 블록체인을 뒷받침하는 언어인 Pint에 대해 자세히 살펴보고 Pint가 어떻게 작동하는지, 그리고 우리가 익숙한 것과 어떤 차이점이 있는지 알아보겠습니다.

Pint는 Essential의 의도 중심 블록체인을 위해 특별히 설계된 특수 제약 모델링 언어입니다. 기존의 필수 스마트 계약 언어와 달리 Pint는 해당 결과를 달성하기 위한 정확한 단계를 지정하지 않고도 상태 변경의 원하는 결과를 정의하는 데 중점을 둡니다. 이러한 초점의 전환은 블록체인 애플리케이션이 개발되고 실행되는 방식에서 더 많은 유연성, 보안 및 효율성을 제공합니다.

파인트를 특별하게 만드는 것은 무엇인가?

Pint는 기존 실행 모델 대신 제약 조건과 술어에 집중하여 블록체인 로직을 처리하는 고유한 방법을 제공합니다. 작동 방식은 다음과 같습니다.

  • 계약 : Pint에서 계약은 블록체인 상태를 업데이트하기 위한 규칙을 정의합니다. 기존 계약과 달리, 이 계약은 변경을 실행하는 방법을 지정하지 않고, 대신 제안된 상태 변경이 특정 기준을 충족하는지 검증합니다.
  • 술어 : 술어는 상태 변경이 유효하기 위해 충족해야 하는 조건입니다. 특정 상태 전환이 발생할 수 있는지 여부를 결정하는 필터 역할을 합니다.
  • 제약 조건 : 제약 조건은 술어의 구성 요소입니다. 이러한 부울 표현식은 술어가 통과하려면 True로 평가되어야 합니다. 예를 들어, 제약 조건은 카운터가 정확히 1만큼 증가하여 상태 업데이트의 일관성을 보장해야 할 수 있습니다.
  • 상태 : 상태 변수는 블록체인의 값을 나타냅니다. 개발자가 사후 상태를 결정하기 위해 사전 상태에 적용되는 실행을 작성하는 기존의 명령형 언어와 달리 Pint는 사전 상태와 사후 상태를 모두 입력으로 제공합니다. 주어진 선언 상태 foo의 경우 foo는 사전 상태를 참조하는 반면 foo'는 사후 상태를 참조합니다.
  • 결정 변수 : 결정 변수를 사용하면 솔버가 술어의 제약 조건을 충족하는 데 필요할 수 있는 추가 데이터를 제공할 수 있습니다. 예를 들어, 토큰 계약의 전송 술어에는 유효한 서명이 필요할 수 있습니다.

Pint에 대한 첫 번째 살펴보기: 간단한 카운터 예시

Pint의 작동 방식을 더 잘 이해하기 위해 간단한 예인 상대 계약을 살펴보겠습니다.

 저장 {
카운터: int,
}

술어 증가 {
상태 카운터: int = storage::counter; // 카운터의 현재 값을 읽습니다.

제약 조건 (counter == nil && counter' == 1) || counter' == counter + 1;
// 이 제약 조건은 카운터가 설정되지 않은 경우 1부터 시작하도록 보장합니다.
// 그렇지 않으면 현재 값을 1 증가시킵니다.
}

저장 블록 :

  • 저장 블록 블록체인에 저장될 단일 정수 변수 카운터를 정의합니다. 여기에 카운터의 현재 값이 보관됩니다.

술어 증가 :

  • 술어 Increment는 카운터를 증가시키기 위한 논리를 정의합니다.
  • 라인 상태 카운터: int = storage::counter;는 저장소에서 카운터의 현재 값을 읽습니다.
  • 제약 조건 (counter == nil && counter' == 1) || counter' == counter + 1;은 카운터가 초기화되지 않은 경우(즉, nil인 경우) 1부터 시작하도록 보장합니다. 그렇지 않은 경우 카운터가 1씩 증가합니다.

간단히 말해서, 이 계약은 "카운터가 아직 없으면 1부터 시작합니다. 카운터가 있으면 현재 값에 1을 더합니다."라고 말합니다. 이 예는 Pint가 개발자가 각 단계(카운터 확인, 카운터에 추가 이더리움 클래식(ETC))를 지정하지 않고도 원하는 결과(카운터 증가)를 정의할 수 있도록 하는 방법을 보여줍니다.

스크래치부터 간단한 암호화폐 구축하기

이제 더 복잡한 예를 들어볼까요? Pint를 사용하여 기본 암호화폐를 만드는 방법을 단계별로 살펴보겠습니다. 첫 번째 원칙부터 시작하겠습니다. 디지털 통화 시스템을 만드는 과제가 주어졌다고 가정해 보겠습니다. 무엇이 필요할까요?

1단계: 핵심 구성 요소 정의

첫째, 우리는 암호화폐의 기본 요소를 결정해야 합니다. 가장 기본적인 수준에서는 다음이 필요합니다.

  1. 화폐 총 공급에 대한 기록 : 이는 화폐 단위가 얼마나 존재하는지 추적합니다.
  2. 잔액을 추적하는 방법 : 각 계좌에 얼마나 많은 현금이 있는지 알아야 합니다.

Pint에서는 저장 블록 사용하여 이를 정의할 수 있습니다.

 저장 {
총 공급량: int,
잔액: (b256 => int),
}
  • total_supply : 이 정수는 통화 총액을 추적합니다.
  • 잔액 : 이것은 각 주소(b256, 256 비트(Bit) 해시 로 표현)를 해당 잔액과 연관시키는 맵(또는 사전)입니다.

2단계: 새 통화 만들기

다음으로, 우리는 새로운 통화를 만드는 방법, 즉 주조가 필요합니다. 통화를 주조할 때, 우리는 총 공급량을 늘리고 수신자의 잔액을 업데이트하고 싶습니다.

다음 단계를 생각해 보겠습니다.

  • 새로 발행된 화폐를 누가 얼마나 받을 것인지 구체적으로 지정해야 합니다.
  • 그런 다음 총 공급량과 수신자의 잔액을 그에 따라 업데이트해야 합니다.

Pint에서 이 논리가 어떻게 표현되는지 살펴보겠습니다.

 술어 민트(Mint) {
var 수신기: b256;
var 금액: int;

상태 수신기 잔액 = mut storage::balances[수신기];
총 공급량 상태 = mut storage::총 공급량;

제약 조건 총 공급량' == 총 공급량 + 금액;
제약 조건 수신자 잔액' == 수신자 잔액 + 금액;
}

분석:

  • 결정 변수 : 수신자와 금액은 수신자의 주소와 민트(Mint) 화폐의 양을 나타냅니다.
  • 상태 변수 : total_supply와 receiver_balance의 상태를 참조하고 이를 변경 가능(mut)으로 선언합니다. 즉, 업데이트가 가능하다는 뜻입니다.
  • 제약사항 :
    — 첫 번째 제약은 총 공급량이 주조된 양만큼 증가하도록 보장합니다.
    — 두 번째 제약은 수신자의 잔액이 발행된 금액으로 업데이트되도록 보장합니다.

그러나 이 예는 이해를 위해 단순화된 것이라는 점에 유의하는 것이 중요합니다. 작성된 계약에는 인증이 내장되어 있지 않습니다. 즉, 누구나 새로운 코인을 민트(Mint) 하거나 어떤 계정에서 다른 계정으로 이체할 수 있습니다. 실제 상황에서 이러한 보안 부족은 심각한 문제가 될 것입니다. 이후 섹션에서는 인증된 사용자만 통화를 민트(Mint) 하거나 이체할 수 있도록 하여 시스템을 보다 안전하게 만드는 방법을 살펴보겠습니다.

3단계: 사용자 간 통화 전송

이제 화폐를 만들 수 있게 되었으니, 다음 단계는 사용자가 서로에게 화폐를 보낼 수 있도록 하는 것입니다. 이를 위해 다음이 필요합니다.

  • 보내는 사람이 보낼 만큼 충분한 통화를 가지고 있는지 확인하세요.
  • 보낸 사람의 잔액에서 해당 금액을 공제합니다.
  • 수취인의 잔액에 해당 금액을 추가합니다.

해당 Pint 코드는 다음과 같습니다.

 술어 보내기 {
var 출처: b256;
var 수신기: b256;
var 금액: int;

상태 from_balance = mut storage::balances[from];
상태 수신기 잔액 = mut storage::balances[수신기];

제약 금액 < from_balance;
제약 조건 from_balance' == from_balance - 금액;
제약 조건 수신자 잔액' == 수신자 잔액 + 금액;
}

분석:

  • 결정 변수 : 보내는 사람, 받는 사람, 금액은 통화를 보내는 사람, 받는 사람, 보내는 양을 지정합니다.
  • 상태 변수 : from_balance와 receiver_balance는 송신자와 수신자의 현재 잔액이며 변경 가능합니다.
  • 제약사항 :
    — 첫 번째 제약 조건은 발신자가 이체를 충당할 만큼 충분한 잔액을 가지고 있는지 확인합니다.
    — 두 번째 제약 조건은 보낸 사람의 잔액에서 해당 금액을 차감합니다.
    — 세 번째 제약 조건은 수취인의 잔액에 해당 금액을 추가합니다.

다시 말해, 여기서의 단순성은 인증을 생략하는데, 이는 실제로는 무단 이체를 방지하는 데 필수적입니다. 이러한 보안 계층을 추가하려면 거래를 허용하기 전에 사용자의 신원을 확인하는 더 복잡한 조건이 필요합니다.

다음은 주조 기능과 전송 기능을 결합한 전체 계약서입니다.

 저장 {
총 공급량: int,
잔액: (b256 => int),
}

술어 민트(Mint) {
var 수신기: b256;
var 금액: int;

상태 수신기 잔액 = mut storage::balances[수신기];
총 공급량 상태 = mut storage::총 공급량;

제약 조건 총 공급량' == 총 공급량 + 금액;
제약 조건 수신자 잔액' == 수신자 잔액 + 금액;
}

술어 보내기 {
var 출처: b256;
var 수신기: b256;
var 금액: int;

상태 from_balance = mut storage::balances[from];
상태 수신기 잔액 = mut storage::balances[수신기];

제약 금액 < from_balance;
제약 조건 from_balance' == from_balance - 금액;
제약 조건 수신자 잔액' == 수신자 잔액 + 금액;
}

이 하위 통화 계약은 기본 암호화폐를 위한 기반 프레임워크를 제공하며, 의도 중심 프로그래밍이 각 작업의 원하는 결과에 초점을 맞춤으로써 어떻게 프로세스를 단순화하는지 보여줍니다.

NFT 계약 구축

이제 기본적인 암호화폐를 구축했으니, 더 복잡하고 미묘한 애플리케이션을 살펴보겠습니다. NFT(Non-Fungible Tokens) 관리입니다. 각 단위가 동일한 대체 가능(fungible) 토큰과 달리 NFT는 고유한 자산을 나타내므로 더 정교한 계약 설계가 필요합니다.

Pint에서 NFT 시스템을 구성하는 방법은 다음과 같습니다.

 std::lib::PredicateAddress를 사용합니다.
std::auth::@auth를 사용합니다.
std::lib::@safe_increment를 사용합니다.
std::lib::@mut_keys를 사용합니다.

저장 {
소유자: (int => b256),
논스: (b256 => int),
}

인터페이스 인증 {
술어 술어 {
// 권한 부여 술어가 출력하는 주소입니다.
// 이는 권한 부여 술어를 이 집합의 술어로 가리킵니다.
// 이 주소를 설정하면 잘못된 술어와 함께 인증을 사용할 수 없습니다.
pub var 주소: { 계약: b256, 주소: b256 };
}
}

술어 민트(Mint) {
var 토큰: int;
var new_owner: b256;

상태 소유자 = mut storage::owners[토큰];
제약 조건 소유자 == nil;
제약 조건 소유자' == new_owner;
}

술어 전송 {
// 금액이 전송되는 주소입니다.
pub var 키: b256;
// 금액을 보낼 주소입니다.
pub var to: b256;
// 전송되는 토큰.
pub var 토큰: int;

상태 소유자 = mut storage::owners[토큰];
상태 논스 = mut storage:: 논스[키];

제약 조건 소유자 == 키;
제약 조건 소유자' == to;
제약 조건 @safe_increment(논스);

// 권한 부여 조건을 확인합니다.
var auth_addr: PredicateAddress;
인터페이스 AuthI = Auth(auth_addr.contract);
술어 A = AuthI::Predicate(auth_addr.addr);

@auth(키; A::주소; 인증 주소; @transfer());
}

술어 취소 {
// 이체 또는 소각을 취소하는 계정입니다.
pub var 키: b256;

상태 논스 = mut storage:: 논스[키];

// 보류 중인 논스 이나
// 화상은 무효화됩니다.
제약 조건 @safe_increment(논스);

// 권한 부여 조건을 확인합니다.
var auth_addr: PredicateAddress;
인터페이스 AuthI = Auth(auth_addr.contract);
술어 A = AuthI::Predicate(auth_addr.addr);

@auth(키; A::주소; 인증 주소; @취소());
}

매크로 @transfer() { { 계약: signed::ADDRESS, 주소: signed::Transfer::ADDRESS } }
매크로 @cancel() { { 계약: signed::ADDRESS, 주소: signed::Cancel::ADDRESS } }

저장 블록 :

  • 소유자: 토큰 ID를 해당 소유자에게 매핑합니다.
  • 논스: 각 계정의 nonce를 추적하여 거래가 고유하고 재생될 수 없음을 보장합니다.

술어 민트(Mint) :

  • 새로운 소유자에게 토큰 ID를 할당하여 새로운 NFT를 생성합니다.
  • 이 제약 조건은 토큰 ID가 이전에 할당되지 않았는지(owner == nil) 확인한 다음 이를 new_owner에 할당합니다.

술어 이전 :

  • 한 소유자로부터 다른 소유자에게 NFT를 이전하는 것을 관리합니다.
  • 현재 소유자만 토큰을 전송할 수 있도록 하는 권한 확인이 포함되어 있습니다.
  • @auth 매크로는 외부 승인 계약과 통합되어 거래를 검증합니다.

술어 취소 :

  • 논스 를 증가시켜 보류 중인 전송이나 소각을 취소할 수 있는 계정이며, 이전에 서명된 모든 거래를 무효화합니다.
  • 또한 승인 시스템과 통합되어 승인된 사용자만 거래를 취소할 수 있도록 보장합니다.

이 NFT 계약은 Pint가 권한 부여 및 거래 무결성 검사와 같은 필수 보안 기능을 통합하는 동시에 보다 복잡한 실제 애플리케이션을 처리할 수 있는 방법을 보여줍니다. 이는 의도 중심 프로그래밍이 시스템이 달성해야 하는 것에 집중하고 기본 프로세스 관리를 언어와 솔버에 맡겨 고급 블록체인 애플리케이션의 개발을 간소화할 수 있는 방법을 보여줍니다.

개발자가 관심을 가져야 하는 이유

Pint에서 예시된 의도 중심 프로그래밍은 블록체인 개발에 대한 새로운 사고방식을 나타냅니다. 실행 세부 정보를 추상화하고 결과에 집중함으로써 개발자는 보다 견고하고 안전하며 유연한 애플리케이션을 만들 수 있습니다. 이 패러다임 전환은 오류 가능성을 줄이고 코딩 프로세스를 단순화하며 보다 혁신적이고 효율적인 솔루션으로의 문을 엽니다.

블록체인 기술이 계속 발전함에 따라 Pint와 같은 언어를 숙달하는 것은 최신 추세를 따라가고 탈중앙화 애플리케이션(DAPPS) 구축하려는 개발자에게 필수적입니다.

마무리 생각

의도 중심 프로그래밍은 스마트 계약을 작성하는 새로운 방법 그 이상입니다. 블록체인 애플리케이션을 설계하고 실행하는 방법에 대한 근본적인 재고입니다. 지시보다는 결과에 집중함으로써 개발자는 현대 블록체인의 역동적이고 복잡한 환경에 더 적합한 보다 안전하고 확장 가능하며 사용자 친화적인 애플리케이션을 만들 수 있습니다.

의도 중심 프로그래밍이 더 보편화됨에 따라, 우리는 그 원칙이 블록체인을 넘어 IoT, AI, 심지어 전통적인 웹 애플리케이션과 같은 소프트웨어 개발의 다른 영역으로 확장되는 것을 볼 수 있을 것입니다. 산업 전반의 개발자들은 절차보다는 결과에 초점을 맞춤으로써 새로운 수준의 효율성, 보안 및 유연성을 열 수 있습니다. 소프트웨어의 미래는 이 패러다임 전환에 의해 정의될 수 있습니다.

Pint에 대해 자세히 알아보고 의도 중심 프로그래밍에 대해 더 자세히 알아보려면 Pint 설명서 에서 자세한 가이드와 예를 확인하세요. Essential에서 배포하는 데 관심이 있는 경우Essential의 공식 설명서를 방문하여 자체 의도 중심 애플리케이션을 빌드하고 배포하기 시작하세요.


의도 중심 프로그래밍에 대한 첫 번째 관점(ft. Pint)은 원래 미디엄(Medium) 의 아이오에스지 벤처스(IOSG Ventures) 에 게재되었으며, 사람들은 이 스토리를 강조하고 응답함으로써 대화를 이어가고 있습니다.

Medium
면책조항: 상기 내용은 작자의 개인적인 의견입니다. 따라서 이는 Followin의 입장과 무관하며 Followin과 관련된 어떠한 투자 제안도 구성하지 않습니다.
라이크
5
즐겨찾기에 추가
1
코멘트
1