이더리움 솔리디티: 메모리 vs 스토리지 & 구조체 내부의 배열을 초기화 하는 방법

Loom Network Korean
Loom Network Korean
5 min readSep 19, 2018

--

이 글은 Georgios Konstantopoulos가 쓴 Ethereum Solidity: Memory vs Storage & How to initialize an array inside a struct를 번역한 글입니다. 오역이 있으면 Private Note 기능으로 알려주세요!

Loom Network의 텔레그램(약 15,000명의 사람들이 있어요! — 한국 텔레그램은 여기로 오세요 😉)에서 사람들은 룸의 로드맵, 블록체인 이론, 이더리움 관련 질문 및 솔리디티 트러블 슈팅과 같은 다양한 주제의 질문을 합니다.

struct 안에서 struct 내부의 array를 초기화하는 방법을 묻는 구체적인 질문이 있었습니다. 이 질문을 한 사람은 자신의 코드를 제공했고, 왜 실행되지 않는지 궁금해했습니다. 저도 여기에 대한 답을 바로 생각해낼 수 없었기에 이 글에서 이 주제를 간단하게 이야기해보려 합니다.

앞서 언급한 실행되지 않는 코드는 아래에서 확인할 수 있습니다. 스스로 해결해보시는 것을 추천합니다(CryptoZombies에서 그동안 연습해왔죠?).

답을 찾으려면 계속 읽어보세요.

잘못된 코드

위의 Fiddle에서 memory는 변수 room을 선언하기 위해 필요한 키워드입니다. Room room과 같이 선언했다면, 컴파일러가 다음과 같은 에러를 리턴할 것입니다:

TypeError: Type struct StructArrayInitWrong.Room memory is not implicitly convertible to expected type struct StructArrayInitWrong.Room storage pointer.

몇 가지 이론

컨트랙트의 storage 변수는 컨트랙트의 상태를 정의하고, sendTransaction 콜을 통해서면 상태를 변경할 수 있습니다[1].

memory 변수는 호출 함수 내부에서만 존재하는 임시 변수입니다(그 밖에서는 정의할 수 없죠). 해당 함수를 탈출하면 지워지고, 일반적으로 storage 변수들을 사용하는 것보다 저렴합니다 — 가스 비용에 대한 자세한 내용은 여기를 참고하세요.

여러분의 이해를 돕기 위해 컨트랙트의 상태에 영향을 주기 위해 함수 안에서 storage 변수를 사용하는 방법에 대한 예제를 하나 살펴도록 하죠.

아래의 Fiddle에서, x의 사본을 함수 g()로 전달했기 때문에, 상태 변수 x는 실행 후에도 값이 변하지 않고 남아 있습니다(이것이 우리가 pure키워드를 사용하는 이유죠).

반면에, 함수 h()에 있는 ystorage로 선언되었습니다. x참조에 의해 전달되었다는 것이지요. 결과적으로, 함수 h()를 호출한 뒤에 상태 변수 x는 수정됩니다.

여러분은 함수 f()를 호출하여 결과를 테스트해볼 수 있고, y[2]의 값을 확인할 수 있습니다. 함수 h()가 호출된 뒤에 함수 g()가 호출되어도 상태 변수의 값은 변하지 않습니다.

이론은 이만하면 충분하고, 원래 질문에 답해봅시다.

구조체를 초기화할 때 players배열을 초기화할 수 없으므로, 다음 단계를 수행해야 합니다:

  1. 비어있는 players배열로 room구조체를 초기화합니다 — 여기이 fiddle에 설명된 것처럼 말이죠.
  2. roomrooms배열로 Push 합니다.
  3. roomplayers배열의 가장 끝에 msg.sender를 Push 합니다(rooms.length-1은 항상 배열의 가장 마지막 요소를 가리킵니다).

아래는 실행되는 코드의 Fiddle입니다:

디버깅을 위해 함수 getRoomPlayers가 추가되었습니다. getRoomPlayers(0)로 초기화를 테스트해 보세요.

여기서 트릭은 new address[](0)가 빈 주소 배열을 위한 메모리를 할당한다는 것입니다. 초기화 이후에는, roomrooms에 추가되고, 스토리지 변수의 일부가 되는 것이죠. 이는 players배열에서 작업하고 값을 Push할 수 있도록 해줍니다.

참고: 만약에 우리가 new uint[](8)을 사용했다면, 8개의 숫자 0을 가지고 있는 배열을 얻었을 것입니다. 이 fiddle에서 테스트해볼 수 있습니다.

오늘은 여기까지입니다. 이것으로 우리가 스토리지/메모리와 관련된 오해를 풀었다면 좋겠습니다. 함수에서 사용하는 방법도 함께 말이죠. 우리의 텔레그램 채널에 여러분의 질문을 올려주세요! 몇 개의 메시지로 답을 하기 어렵다면 질문에 관련된 글을 올리겠습니다(또는 크립토좀비 강의로 말이죠!)

Loom Network는 고성능 디앱을 확장하기 위한 멀티체인 상호운용 플랫폼입니다 — 이미 상용 가능한 상태이며, 감사 및 실제 테스트를 거쳤습니다.

Loom 베이스체인에 여러분의 디앱을 한 번 배포하고 나면, 오늘날 모든 주요 블록체인에 걸쳐 가능한 가장 광범위한 사용자 기반에 접근할 수 있습니다.

Loom Network를 처음 접하시나요? 여기서 시작하세요.

LOOM 토큰을 스테이킹해서 베이스체인을 보호하는 데 참여하고 싶으신가요? 여기서 그 방법을 알아보세요.

우리가 하는 일이 마음에 드시나요? 그렇다면 어서 우리의 프라이빗 메일링 리스트에 가입하고, 우리가 계속 전달하는 모든 업데이트를 계속 받아보세요.

--

--