이전에 작성했던 프록시 패턴을 실습해보도록 하겠습니다.
https://dev-dean-k.tistory.com/86
[Solidity] 프록시 패턴(Proxy Pattern)
스마트 컨트랙트의 가장 큰 특징은 한번 배포되면 컨트랙트 코드의 수정이 불가하다는 것입니다. 그렇기 때문에 배포 전에 엄격한 테스트가 필요하며 만약 그랬다고 하더라도 예기치 못한 수정
dev-dean-k.tistory.com
먼저 필요한 패키지를 설치합니다.
npm install @openzeppelin/contracts
npm install --save-dev @openzeppelin/hardhat-upgrades
하드햇에서 2개의 컨트랙트 Box와 수정 버전인 BoxV2를 작성합니다.
Box
//SPDX-License-Identifier: Unlicense
pragma solidity ^0.8.4;
contract Box {
uint public val;
function initialize(uint _val) external {
val = _val;
}
}
BoxV2
//SPDX-License-Identifier: Unlicense
pragma solidity ^0.8.4;
contract BoxV2 {
uint public val;
function inc() external {
val += 1;
}
}
프록시 패턴을 사용할 때는 생성자를 사용하지 않고 초기화 함수를 따로 생성하는데 그 이유에 대해서는 차후에 다루도록 하겠습니다. 또한 Box에서 사용된 initalize를 V2에서 사용하지 않는 이유는 초기화 함수는 단 1번만 호출되어야하기 때문입니다.
scripts/deploy.js 파일을 생성한뒤 배포 스크립트를 작성합니다.
const { ethers, upgrades } = require("hardhat");
async function main() {
const Box = await ethers.getContractFactory("Box");
const box = await upgrades.deployProxy(Box, [42], { initializer: "initialize" });
await box.deployed();
console.log("Box deployed to:", box.address);
}
// We recommend this pattern to be able to use async/await everywhere
// and properly handle errors.
main()
.then(() => process.exit(0))
.catch((error) => {
console.error(error);
process.exit(1);
});
hardhat.config.js파일에 다음과 같이 추가해주시고 테스트 넷에 배포해보겠습니다.
require("@nomiclabs/hardhat-ethers");
require("@nomiclabs/hardhat-etherscan");
require("@openzeppelin/hardhat-upgrades");
저는 폴리곤 테스트넷인 mumbai에 배포하겠습니다.
npx hardhat run scripts/deploy.js --network mumbai
polyscan에서 배포된 컨트랙트를 확인합니다. from을 보면 3개의 컨트랙트가 배포된 것을 확인할 수 있습니다.
3개의 컨트랙트는 작성했던 Box와 Proxy 그리고 ProxyAdmin입니다.
Box 컨트랙트에서 ReadContract를 확인해보면 val 값이 0인 것을 볼 수 있는데 이는 Box 컨트랙트는 storage를 사용하지 않고 storage는 프록시에 저장되기 때문입니다.
프록시 컨트랙트에서 Is this a proxy?를 클릭 후 Contract탭을 확인합니다.
Contract 탭에 들어가면 새로운 Read as Proxy, Write as Proxy 탭에 새로 생긴 것을 확인할 수 있습니다.
프록시에 deploy 스크립트에서 배포 시 입력했던 42가 저장되어 있는 것을 볼 수 있습니다.
이제 컨트랙트를 BoxV2로 교체 해보겠습니다.
새로운 스크립트를 작성 후 배포합니다.
const { ethers, upgrades } = require("hardhat");
const PROXY_ADR = "0x3f5F0ebA1bc4A2F3A0bf674F80181602e1b48743"
async function main() {
const BoxV2 = await ethers.getContractFactory("BoxV2");
await upgrades.upgradeProxy(PROXY_ADR, BoxV2);
console.log("Box upgraded");
}
// We recommend this pattern to be able to use async/await everywhere
// and properly handle errors.
main()
.then(() => process.exit(0))
.catch((error) => {
console.error(error);
process.exit(1);
});
npx hardhat run scripts/upgrade_box.js --network mumbai
배포 후 2개의 트랜잭션이 발생했는데 1개는 새로 작성한 BoxV2이며 하나는 프록시를 업그레이드 하는 트랜잭션입니다.
프록시 컨트랙트에서 Write as a proxy 탭을 들어가면 BoxV2의 함수인 inc를 볼 수 있습니다.
Connect to Web3를 눌러 메타마스크를 연결한 후 inc를 실행합니다.
트랜잭션이 완료된 후 val 값이 43으로 변경된 것을 확인할 수 있습니다.
여기까지 간단하게 프록시 패턴을 실습해보았습니다.
'블록체인 > 이더리움' 카테고리의 다른 글
Re-Entrancy Attack (0) | 2022.07.10 |
---|---|
머클트리 (0) | 2022.06.30 |
솔리디티 프록시 패턴(Proxy Pattern) (0) | 2022.06.25 |
IPFS? (0) | 2022.06.16 |
UTXO(비트코인) vs Account Balance(이더리움) (0) | 2022.06.15 |