Rust 스마트 컨트랙트 개발일지 (9)
BlockSec
2022-04-01 11:39
本文约2024字,阅读全文需要约8分钟
프로그램 유지 관리의 근본적인 문제는 버그 수정이 항상 (20-50)% 확률로 새로운 버그를 도입한다는 것입니다.

보조 제목

1. 계약 업그레이드의 필요성

보조 제목

2. Solidity 계약의 일반적인 업그레이드 방법

이더리움에서 스마트 계약은 변경할 수 없으며 일단 체인에 배포되면 아무도 변경할 수 없습니다.

따라서 계약에 허점이 있거나 계약에 새로운 기능을 추가해야 하는 경우 계약 코드를 수정하는 방법은 무엇입니까? 해결책은 새로운 계약을 블록체인에 배포하는 것입니다.

이 방법의 문제는 Solidity가 계약을 배포할 때마다 계약에 고유한 주소가 할당된다는 것입니다. 따라서 이 계약을 사용하는 모든 DApp은 새로운 계약에 맞게 계약 주소를 수정해야 합니다. 또한 이전 버전의 계약 상태를 새 버전의 계약으로 마이그레이션해야 합니다. 더 복잡한 상태의 계약 마이그레이션은 많은 작업이 필요하고 오류가 발생하기 쉬우며 데이터 복사에 대한 가스 비용이 발생합니다. 높다.

따라서 일반적으로 데이터와 로직이 분리되어 데이터는 어떠한 로직도 처리하지 않는 컨트랙트(상태 컨트랙트)에 저장하고, 모든 로직은 다른 컨트랙트(로직 컨트랙트)에서 구현되는 아키텍처를 채택합니다. 일반적으로 컨트랙트 업그레이드는 로직을 수정하는데, 이 아키텍처를 사용하면 상태 마이그레이션에 대한 걱정 없이 로직 컨트랙트만 업그레이드하면 됩니다.

이를 해결하기 위해 대리계약(Proxy Contract)을 사용할 수 있으며 구체적인 구조는 아래 그림과 같다.

프록시 계약은 데이터를 저장하는 데 사용되고 delegatecall은 논리 계약 A를 호출하는 데 사용되므로 계약 A가 읽고 쓴 데이터가 프록시 계약에 저장됩니다. 논리 계약을 업그레이드해야 하는 경우 새 계약 B를 배포한 다음 프록시 계약이 새 논리 계약 B를 가리키도록 트랜잭션을 프록시 계약으로 보냅니다.

3. NEAR 계약 업그레이드의 일반적인 방법

다음으로 StatusMessage 프로젝트를 예로 들어 NEAR 컨트랙트의 일반적인 업그레이드 방법을 소개하겠습니다.StatusMessage 컨트랙트 코드는 다음과 같습니다.

먼저 컴파일된 컨트랙트를 테스트넷에 배포합니다.

거래는 다음과 같습니다

그런 다음 set_status 메서드를 호출하여 계약에 데이터를 저장합니다.

거래는 다음과 같습니다

다음으로 두 가지 다른 계약 업그레이드 시나리오에 대해 자세히 논의합니다.

3.1 계약 데이터 구조가 수정되지 않았습니다.

예를 들어 다음과 같은 기능을 추가합니다.

컴파일 후 배포를 사용하여 재배포합니다.

컴파일 후 배포를 사용하여 재배포합니다.

그런 다음 get_status 메서드를 호출하여 이전에 작성된 데이터를 읽습니다.

원래 계약의 데이터를 성공적으로 읽을 수 있습니다.

이는 NEAR 컨트랙트가 반복적으로 배포될 수 있기 때문인데, 계정(주소)이 이미 컨트랙트를 배포한 경우 다시 near 배포 명령을 호출하면 새 계약 코드를 해당 계정에 배포할 수 있습니다. 데이터 구조를 수정하지 않고 컨트랙트 논리만 수정하면 Near Deployment를 직접 사용하여 새 코드를 배포할 수 있습니다.

3.2 컨트랙트 데이터 구조 수정

계약을 업그레이드하고, 원래 데이터 구조를 수정하고, 레코드를 제거하고, 슬로건과 약력을 추가했습니다.

다시 재배포를 시도합니다.

계약은 여전히 ​​성공적으로 배포됩니다.

그러나 저장된 데이터를 읽기 위해 get_tagline 메서드를 호출합니다.

문제가 발생했으며 오류 메시지는 다음과 같습니다.

Cannot deserialize the contract state.

특정 트랜잭션을 참조하십시오.

https://explorer.testnet.near.org/transactions/4hQQ1zAwU5bsbfb6tA6DQDqjmFcHsBwaBctdHaPiCKHu

이는 컨트랙트의 상태가 직렬화된 데이터 형태로 영속적으로 저장되기 때문이며, 컨트랙트 재배포 후 코드의 데이터 구조는 변경되지만 상태는 변경되지 않습니다. 오류가 발생합니다.

3.3 마이그레이션 업그레이드 스마트 계약

NEAR는 계약을 업그레이드하는 데 도움이 되는 Migrate 방법을 제공합니다. 3.2의 오류에 대해 새 계약에 마이그레이션 방법을 추가합니다.

코드의 #[init(ignore_state)] 는 마이그레이션 함수가 실행되기 전에 상태를 로드하지 않는다는 의미입니다. 다음으로 계약을 재배포하지만 배포하는 동안 마이그레이션 메서드를 호출합니다.

아래와 같이 계약이 성공적으로 배포되었습니다.

새로운 데이터 태그라인을 얻기 위해 계약의 새로운 메서드 get_tagline을 호출하려고 합니다.

메서드가 성공적으로 호출되고 이전 계약 데이터도 새 계약으로 마이그레이션되는 것을 볼 수 있습니다.

4. 계약 업그레이드에 대한 보안 고려 사항

계약 보안 업그레이드는 먼저 권한 제어를 고려해야 하며 일반적으로 계약은 개발자 또는 DAO에 의해서만 업그레이드될 수 있습니다. 마지막 기간Rust 스마트 컨트랙트 육성일지 (8) 컨트랙트 보안 권한 통제특권 기능의 접근 제어를 도입 일반 계약의 업그레이드 기능은 유일한 소유자 기능으로 소유자만 호출할 수 있도록 합니다.

가급적 컨트랙트의 소유자를 DAO로 설정하고, 제안과 투표를 통해 컨트랙트를 공동 관리하는 것을 권장합니다. 소유자가 개인 계정으로 설정되기 때문에 계약은 고도로 중앙 집중화되어 있으며 소유자는 계약 데이터를 마음대로 수정할 수 있으며 소유자의 개인 키를 잃을 위험도 있습니다.

또한 개발자는 계약 마이그레이션을 수행할 때 다음 제안 사항을 고려할 수도 있습니다.

  • 마이그레이션 기능이 실행되기 전에 상태가 로드되지 않도록 마이그레이션 기능 앞에 #[init(ignore_state)]를 추가하십시오.

  • 마이그레이션이 완료된 후 마이그레이션 기능이 한 번만 호출되도록 마이그레이션 기능을 최대한 삭제하십시오.

  • 새로 추가된 데이터 구조는 마이그레이션 중에 초기화됩니다.

BlockSec
作者文库