Solidity v0.7.0 Breaking Changes

Solidity v0.7.0 Breaking Changes

이 절은 Solidity 버전 0.7.0에서 도입된 주요 breaking change와, 그 변경의 이유, 그리고 영향을 받는 코드를 업데이트하는 방법을 강조해요. 전체 목록은 릴리스 changelog를 확인해요.

출처: 문서

본문

이 절은 Solidity 버전 0.7.0에서 도입된 주요 breaking change와 그 뒤의 이유, 그리고 영향을 받는 코드를 업데이트하는 방법을 강조해요. 전체 목록은 릴리스 changelog를 확인해요.

의미의 조용한 변경 (Silent Changes of the Semantics)

  • 리터럴을 비-리터럴로 지수화하거나 시프트하는 것(예: 1 << x 또는 2 ** x)은 이제 항상 uint256(음이 아닌 리터럴) 또는 int256(음수 리터럴) 타입을 사용해 연산을 수행해요. 이전에는 시프트 양/지수의 타입으로 연산이 수행돼 오해의 소지가 있었어요.

문법 변경 (Changes to the Syntax)

  • 외부 함수 및 컨트랙트 생성 호출에서 Ether와 가스는 이제 새 구문으로 지정돼요: x.f{gas: 10000, value: 2 ether}(arg1, arg2). 옛 구문 x.f.gas(10000).value(2 ether)(arg1, arg2)은 에러를 일으켜요.
  • 전역 변수 now는 이제 비권장이며, 그 자리에 block.timestamp를 사용해야 해요. 단일 식별자 now는 전역 변수로는 너무 일반적이고, 트랜잭션 처리 중에 바뀌는 것처럼 인상줄 수 있는 반면, block.timestamp는 블록의 속성일 뿐이라는 사실을 정확히 반영해요.
  • 변수의 NatSpec 주석은 public 상태 변수에만 허용되고, 로컬 또는 내부 변수에는 허용되지 않아요.
  • gwei 토큰은 이제 키워드예요(예: 숫자 2 gwei를 지정하는 데 사용) 그리고 식별자로 사용할 수 없어요.
  • 문자열 리터럴은 이제 인쇄 가능한 ASCII 문자만 포함할 수 있으며, 여기에는 16진수(\xff)와 유니코드 이스케이프(\u20ac) 같은 다양한 이스케이프 시퀀스도 포함돼요.
  • 유효한 UTF-8 시퀀스를 수용하기 위해 유니코드 문자열 리터럴이 이제 지원돼요. unicode 접두사로 식별돼요: unicode"Hello 😃".
  • 상태 가변성(State Mutability): 함수의 상태 가변성은 이제 상속 중에 제한할 수 있어요. 기본 상태 가변성을 가진 함수는 pure와 view 함수로 오버라이드될 수 있고, view 함수는 pure 함수로 오버라이드될 수 있어요. 동시에 public 상태 변수는 view로 간주되고, 상수라면 pure로도 간주돼요.

인라인 어셈블리 (Inline Assembly)

  • 인라인 어셈블리에서 사용자 정의 함수와 변수 이름에 .을 허용하지 않아요. Solidity를 Yul-only 모드로 사용하면 여전히 유효해요.
  • 스토리지 포인터 변수 x의 슬롯과 오프셋은 x_slot과 x_offset 대신 x.slot과 x.offset으로 접근해요.

사용하지 않거나 안전하지 않은 기능의 제거 (Removal of Unused or Unsafe Features)

스토리지 밖의 매핑 (Mappings outside Storage)

  • 구조체나 배열이 매핑을 포함하면 스토리지에서만 사용할 수 있어요. 이전에는 매핑 멤버가 메모리에서 조용히 건너뛰어져 혼란스럽고 오류가 나기 쉬웠어요.
  • 매핑을 포함하는 구조체나 배열에 대한 스토리지에서의 할당은 동작하지 않아요. 이전에는 복사 연산 중 매핑이 조용히 건너뛰어져 오해의 소지가 있고 오류가 나기 쉬웠어요.

함수와 이벤트 (Functions and Events)

  • 생성자에는 더 이상 가시성(public/internal)이 필요하지 않아요. 컨트랙트가 생성되는 것을 막으려면 abstract로 표시할 수 있어요. 이로써 생성자의 가시성 개념은 쓸모없어졌어요.
  • 타입 검사기(Type Checker): 라이브러리 함수에 virtual을 허용하지 않아요. 라이브러리는 상속될 수 없으므로 라이브러리 함수는 virtual이면 안 돼요.
  • 같은 상속 계층에서 같은 이름과 파라미터 타입을 가진 여러 이벤트를 허용하지 않아요.
  • using A for B는 그것이 언급된 컨트랙트에만 영향을 줘요. 이전에는 그 효과가 상속됐어요. 이제는 그 기능을 사용하는 모든 파생 컨트랙트에서 using 문을 반복해야 해요.

표현식 (Expressions)

  • 부호 있는 타입으로 시프트하는 것을 허용하지 않아요. 이전에는 음수 양으로 시프트하는 것이 허용됐지만 런타임에 revert했어요.
  • finney와 szabo 단위가 제거됐어요. 그것들은 거의 사용되지 않고 실제 금액을 쉽게 보이게 하지 못해요. 대신 1e20 같은 명시적 값이나 매우 흔한 gwei를 사용할 수 있어요.

선언 (Declarations)

  • var 키워드를 더 이상 사용할 수 없어요. 이전에는 이 키워드가 파싱되지만 타입 에러와 사용할 타입에 대한 제안을 내놓았어요. 이제는 파서 에러를 일으켜요.

인터페이스 변경 (Interface Changes)

  • JSON AST: 16진 문자열 리터럴을 kind: "hexString"으로 표시해요.
  • JSON AST: 값이 null인 멤버를 JSON 출력에서 제거해요.
  • NatSpec: 생성자와 함수가 일관된 userdoc 출력을 가져요.

코드를 업데이트하는 방법 (How to update your code)

이 절은 각 breaking change에 대해 이전 코드를 업데이트하는 방법을 상세히 설명해요.

  • x.f.value(...)()를 x.f{value: ...}()로 바꿔요. 마찬가지로 (new C).value(...)()를 new C{value: ...}()로, x.f.gas(...).value(...)()를 x.f{gas: ..., value: ...}()로 바꿔요.
  • now를 block.timestamp로 바꿔요.
  • 시프트 연산자에서 오른쪽 피연산자의 타입을 부호 없는 타입으로 바꿔요. 예를 들어 x >> (256 - y)를 x >> uint(256 - y)로 바꿔요.
  • 필요하면 모든 파생 컨트랙트에서 using A for B 문을 반복해요.
  • 모든 생성자에서 public 키워드를 제거해요.
  • 모든 생성자에서 internal 키워드를 제거하고 컨트랙트에 abstract를 추가해요(아직 없다면).
  • 인라인 어셈블리에서 _slot과 _offset 접미사를 각각 .slot과 .offset으로 바꿔요.

더 알아보기 (Learn more)