diff --git a/content/posts/DAO_Corollary.md b/content/posts/DAO_Corollary.md new file mode 100644 index 0000000..6e8dcb0 --- /dev/null +++ b/content/posts/DAO_Corollary.md @@ -0,0 +1,79 @@ +--- +title: "DAO_Corollary" +date: 2021-11-10T09:30:40-08:00 +draft: false +--- + +# DAO Corollary, For Teams + +> F.K.A. Amdahl's Corollary + +The most efficient way to implement a piece of software is to do it all yourself. + +No time is wasted communicating (or arguing); everything that needs to be done is done by the same person, which increases their ability to maintain the software; and the code is by default way more consistent. + +Turns out “more efficient” doesn’t mean “faster”. When there are more people working on the same problem, we can parallelized more at once. + +When we break work up across a team, in order to optimise for the team, we often have to put _more_ work in, individually, to ensure that the work can be efficiently parallelized. This includes explaining concepts, team meetings, code review, pair programming, etc. But by putting that work in, we make the work more parallelized, speeding up and allowing us to make greater gains in the future. + +## An Aside: Amdahl’s Law + +Amdahl’s law can be formulated as follows: + +Slatency\=1(1\-p)+ps + +In words, it predicts the maximum potential speedup (Slatency), given a proportion of the task, p, that will benefit from improved (either more or better) resources, and a parallel speedup factor, s. + +To demonstrate, if we can speed up 10% of the task (p\=0.1) by a factor of 5 (s\=5), we get the following: + +Slatency\=1(1\-0.1)+0.15≈1.09 + +That’s about an 9% speedup. Eh, fair enough. If we can swing it, sounds good. + +However, if we can speed up 90% of the task (p\=0.9) by a factor of 5 (s\=5), we get the following: + +Slatency\=1(1\-0.9)+0.95≈3.58 + +That’s roughly a 250% increase! Big enough that it’s actually worth creating twice as much work; it still pays off, assuming the value of the work dwarfs the cost of the resources. + +s→∞, which means ps→0, so we can also drop the ps term if we can afford potentially infinite resources at no additional cost. + +Slatency\=11\-0.9\=10 + +In other words, if 90% of the work can be parallelised, we can achieve a theoretical maximum speedup of 10x, or a 900% increase. This is highly unlikely, but gives us a useful upper bound to help us identify where the bottleneck lies. + +## Generalising To The Amount Of Work + +Typically, we start off with a completely serial process. In order to parallelize, we need to do _more_ work. It doesn’t come for free. + +This means that when computing s, the parallel speedup, we should divide it by the cost of parallelisation. For example, if the cost is 2, that means that making the work _parallelisable_ (without actually increasing the number of resources) makes the parallel portion take twice as long as it used to. (The serial portion is unchanged.) + +So, if we take the example from earlier, where 90% of the work is parallelisable _but_ it costs twice as much to parallelize, we’ll get the following result: + +Slatency\=1(1\-0.9)+0.952≈2.18 + +It’s still about a 117% increase in output! + +However, if p\=0.1, then there’s really very little point in adding more resources. + +Slatency\=1(1\-0.1)+0.152≈1.06 + +And if the cost of parallelization is greater than the potential speedup, bad things happen: + +Slatency\=1(1\-0.1)+0.1520≈0.769 + +Adding 4 more resources slows us down by 23%. Many of us have seen this happen in practice with poor parallelization techniques—poor usage of locks, resource contention (especially with regards to I/O), or even redundant work due to mismanaged job distribution. + +## So, What Does It All Mean? + +Amdahl’s law tells us something very insightful: when the value of your work is much greater than the cost, you should optimise for parallelism, not efficiency. The cost of a weekly two-hour team meeting is high (typically in the $1000s each time), but if it means that you can have 7 people on the team, not 3, it’s often worth it. + +[Delivering faster means you can deliver more.](https://en.wikipedia.org/wiki/Gustafson's_law) + +Don’t stop at optimizing meetings. Pairing costs money, but it usually means way better team cohesion, which improves your ability to parallelise. Better to have 10 people working on 5 problems and doing a better job than it is to have 10 people working on 10 problems. + +The former will lead to fewer conflicts, fewer defects and a much more motivated team. In other words (and by words I mean algebra), p and s both go up way faster than the amount of work. + +Yes, meetings and other collaboration enhancers are boring. But they’re necessary. Just make sure you never lose sight of their purpose: to build a shared vision and style of work so that the team (or the organization) works as one unit. This allows us to grow the team and benefit from the increased number of people on the job. + +Conversely, if all the knowledge of how the product works is in one person’s head, p≈0. While there’s no impact to efficiency this way, it limits our ability to produce, because one person can only do so much. Adding more people just makes things slower. diff --git a/content/posts/Problems_Are_hard.md b/content/posts/Problems_Are_hard.md new file mode 100644 index 0000000..9261a1e --- /dev/null +++ b/content/posts/Problems_Are_hard.md @@ -0,0 +1,24 @@ +--- +title: "Problems_Are_hard" +date: 2021-11-10T09:28:13-08:00 +draft: false +--- + +# All Problems Are Hard + +> Aren’t all problems hard? + +Say a customer reports a bug, and you’ve got to fix it. You can fix it. You know you can fix it. Maybe it’ll take an hour, maybe it’ll take a day, maybe a week. But you’ll narrow it down, figure out the smallest possible increment of work you can do to remedy the problem, and then you’ll do it. And as much as it pains me to say it, because I want to be able to check that box that said I did the thing… this is the easy part. + +Once in a while, when we’re feeling brave, we also try to tackle the hard problem. We try to answer the questions that we usually avoid. + +- Why was this bug caused in the first place? +- Did we know about it before the customer hit it, and if so, why didn’t we do anything about it? +- Was the customer upset? Did we make sure they’re happy again? +- Can we fix not just this bug, but all classes of this bug in the future? +- What are the root causes ingrained in our culture that made this bug possible? +- Can we change our culture to ensure this doesn’t happen again? + +These are the hard problems. We can’t always solve them. Maybe they’re too entrenched, maybe you don’t have the power, maybe others don’t see the problem, maybe they’re too expensive to fix. Or maybe you just don’t have the energy to fight this battle. We can’t fight all of them, after all. + +That way lies burnout. diff --git a/content/posts/evm-lowlevel.md b/content/posts/evm-lowlevel.md index 61e8686..16aa72c 100644 --- a/content/posts/evm-lowlevel.md +++ b/content/posts/evm-lowlevel.md @@ -6,20 +6,18 @@ For writers of line debuggers and other debugging-related utilities.  - --- - ## Purpose of this document The point of this document is to explain representation of data in Solidity for the purposes of locating and decoding it; more specifically, for writing a line -debugger that does such. As such, other information about the type system or +debugger that does such. As such, other information about the type system or data layout that aren't necessary for that may be skipped; and where location is not entirely predictable but may be determined by other -systems of the debugger, we may rely on that. See the +systems of the debugger, we may rely on that. See the [Solidity documentation](https://docs.soliditylang.org/) for things not covered here, particularly the [section on types](https://docs.soliditylang.org/en/v0.8.9/types.html) @@ -43,85 +41,83 @@ there, it's not our concern. _**Note**: This document pertains to **Solidity v0.8.9**, current as of this writing._ - - ## Contents -* [Purpose of this document](#user-content-purpose-of-this-document) -* [Contents](#user-content-contents) -* [Locations: Basics](#user-content-locations-basics) -* [Types Overview](#user-content-types-overview) - * [Terminology](#user-content-types-overview-terminology) - * [Types and locations](#user-content-types-overview-types-and-locations) - * [Table of types and locations](#user-content-types-overview-types-and-locations-table-of-types-and-locations) - * [Overview of the types: Direct types](#user-content-types-overview-overview-of-the-types-direct-types) - * [Basics of direct types: Packing and padding](#user-content-types-overview-overview-of-the-types-direct-types-basics-of-direct-types-packing-and-padding) - * [Table of direct types](#user-content-types-overview-overview-of-the-types-direct-types-table-of-direct-types) - * [Representations of direct types](#user-content-types-overview-overview-of-the-types-direct-types-representations-of-direct-types) - * [Presently unstoreable functions](#user-content-types-overview-overview-of-the-types-direct-types-presently-unstoreable-functions) - * [Overview of the types: Multivalue types](#user-content-types-overview-overview-of-the-types-multivalue-types) - * [Overview of the types: Lookup types](#user-content-types-overview-overview-of-the-types-lookup-types) - * [Table of lookup types](#user-content-types-overview-overview-of-the-types-lookup-types-table-of-lookup-types) - * [Overview of the types: Pointer types](#user-content-types-overview-overview-of-the-types-pointer-types) - * [Table of pointer types](#user-content-types-overview-overview-of-the-types-pointer-types-table-of-pointer-types) -* [Locations in Detail](#user-content-locations-in-detail) - * [The stack in detail](#user-content-locations-in-detail-the-stack-in-detail) - * [The stack: Direct types and pointer types](#user-content-locations-in-detail-the-stack-in-detail-the-stack-direct-types-and-pointer-types) - * [The stack: Data layout](#user-content-locations-in-detail-the-stack-in-detail-the-stack-data-layout) - * [Code in detail](#user-content-locations-in-detail-code-in-detail) - * [Code: direct types](#user-content-locations-in-detail-code-in-detail-code-direct-types) - * [Code: data layout](#user-content-locations-in-detail-code-in-detail-code-data-layout) - * [Memory in detail](#user-content-locations-in-detail-memory-in-detail) - * [Memory: Direct types and pointer types](#user-content-locations-in-detail-memory-in-detail-memory-direct-types-and-pointer-types) - * [Layout of immutables in memory](#user-content-locations-in-detail-memory-in-detail-layout-of-immutables-in-memory) - * [Memory: Multivalue types](#user-content-locations-in-detail-memory-in-detail-memory-multivalue-types) - * [Memory: Lookup types](#user-content-locations-in-detail-memory-in-detail-memory-lookup-types) - * [Pointers to memory](#user-content-locations-in-detail-memory-in-detail-pointers-to-memory) - * [Calldata in detail](#user-content-locations-in-detail-calldata-in-detail) - * [Slots in calldata and the offset](#user-content-locations-in-detail-calldata-in-detail-slots-in-calldata-and-the-offset) - * [Calldata: Direct types and pointer types](#user-content-locations-in-detail-calldata-in-detail-calldata-direct-types-and-pointer-types) - * [Calldata: Multivalue and lookup types (reference types)](#user-content-locations-in-detail-calldata-in-detail-calldata-multivalue-and-lookup-types-reference-types) - * [The special variable `msg.data`](#user-content-locations-in-detail-calldata-in-detail-calldata-multivalue-and-lookup-types-reference-types-the-special-variable-msg-data) - * [Pointers to calldata](#user-content-locations-in-detail-calldata-in-detail-pointers-to-calldata) - * [Pointers to calldata from calldata](#user-content-locations-in-detail-calldata-in-detail-pointers-to-calldata-from-calldata) - * [Pointers to calldata from the stack](#user-content-locations-in-detail-calldata-in-detail-pointers-to-calldata-from-the-stack) - * [Storage in detail](#user-content-locations-in-detail-storage-in-detail) - * [Storage: Data layout](#user-content-locations-in-detail-storage-in-detail-storage-data-layout) - * [Storage: Direct types](#user-content-locations-in-detail-storage-in-detail-storage-direct-types) - * [Storage: Multivalue types](#user-content-locations-in-detail-storage-in-detail-storage-multivalue-types) - * [Storage: Lookup types](#user-content-locations-in-detail-storage-in-detail-storage-lookup-types) - * [Pointers to storage](#user-content-locations-in-detail-storage-in-detail-pointers-to-storage) +- [Purpose of this document](#user-content-purpose-of-this-document) +- [Contents](#user-content-contents) +- [Locations: Basics](#user-content-locations-basics) +- [Types Overview](#user-content-types-overview) + - [Terminology](#user-content-types-overview-terminology) + - [Types and locations](#user-content-types-overview-types-and-locations) + - [Table of types and locations](#user-content-types-overview-types-and-locations-table-of-types-and-locations) + - [Overview of the types: Direct types](#user-content-types-overview-overview-of-the-types-direct-types) + - [Basics of direct types: Packing and padding](#user-content-types-overview-overview-of-the-types-direct-types-basics-of-direct-types-packing-and-padding) + - [Table of direct types](#user-content-types-overview-overview-of-the-types-direct-types-table-of-direct-types) + - [Representations of direct types](#user-content-types-overview-overview-of-the-types-direct-types-representations-of-direct-types) + - [Presently unstoreable functions](#user-content-types-overview-overview-of-the-types-direct-types-presently-unstoreable-functions) + - [Overview of the types: Multivalue types](#user-content-types-overview-overview-of-the-types-multivalue-types) + - [Overview of the types: Lookup types](#user-content-types-overview-overview-of-the-types-lookup-types) + - [Table of lookup types](#user-content-types-overview-overview-of-the-types-lookup-types-table-of-lookup-types) + - [Overview of the types: Pointer types](#user-content-types-overview-overview-of-the-types-pointer-types) + - [Table of pointer types](#user-content-types-overview-overview-of-the-types-pointer-types-table-of-pointer-types) +- [Locations in Detail](#user-content-locations-in-detail) + - [The stack in detail](#user-content-locations-in-detail-the-stack-in-detail) + - [The stack: Direct types and pointer types](#user-content-locations-in-detail-the-stack-in-detail-the-stack-direct-types-and-pointer-types) + - [The stack: Data layout](#user-content-locations-in-detail-the-stack-in-detail-the-stack-data-layout) + - [Code in detail](#user-content-locations-in-detail-code-in-detail) + - [Code: direct types](#user-content-locations-in-detail-code-in-detail-code-direct-types) + - [Code: data layout](#user-content-locations-in-detail-code-in-detail-code-data-layout) + - [Memory in detail](#user-content-locations-in-detail-memory-in-detail) + - [Memory: Direct types and pointer types](#user-content-locations-in-detail-memory-in-detail-memory-direct-types-and-pointer-types) + - [Layout of immutables in memory](#user-content-locations-in-detail-memory-in-detail-layout-of-immutables-in-memory) + - [Memory: Multivalue types](#user-content-locations-in-detail-memory-in-detail-memory-multivalue-types) + - [Memory: Lookup types](#user-content-locations-in-detail-memory-in-detail-memory-lookup-types) + - [Pointers to memory](#user-content-locations-in-detail-memory-in-detail-pointers-to-memory) + - [Calldata in detail](#user-content-locations-in-detail-calldata-in-detail) + - [Slots in calldata and the offset](#user-content-locations-in-detail-calldata-in-detail-slots-in-calldata-and-the-offset) + - [Calldata: Direct types and pointer types](#user-content-locations-in-detail-calldata-in-detail-calldata-direct-types-and-pointer-types) + - [Calldata: Multivalue and lookup types (reference types)](#user-content-locations-in-detail-calldata-in-detail-calldata-multivalue-and-lookup-types-reference-types) + - [The special variable `msg.data`](#user-content-locations-in-detail-calldata-in-detail-calldata-multivalue-and-lookup-types-reference-types-the-special-variable-msg-data) + - [Pointers to calldata](#user-content-locations-in-detail-calldata-in-detail-pointers-to-calldata) + - [Pointers to calldata from calldata](#user-content-locations-in-detail-calldata-in-detail-pointers-to-calldata-from-calldata) + - [Pointers to calldata from the stack](#user-content-locations-in-detail-calldata-in-detail-pointers-to-calldata-from-the-stack) + - [Storage in detail](#user-content-locations-in-detail-storage-in-detail) + - [Storage: Data layout](#user-content-locations-in-detail-storage-in-detail-storage-data-layout) + - [Storage: Direct types](#user-content-locations-in-detail-storage-in-detail-storage-direct-types) + - [Storage: Multivalue types](#user-content-locations-in-detail-storage-in-detail-storage-multivalue-types) + - [Storage: Lookup types](#user-content-locations-in-detail-storage-in-detail-storage-lookup-types) + - [Pointers to storage](#user-content-locations-in-detail-storage-in-detail-pointers-to-storage) - ## Locations: Basics + [ [∧](#user-content-contents) _Back to contents_ ] -The EVM has a number of locations where data can be stored. We will be +The EVM has a number of locations where data can be stored. We will be concerned with five of them: The stack, storage, memory, calldata, and code. -(We will ignore returndata. There are also some other "special locations" that +(We will ignore returndata. There are also some other "special locations" that I will mention briefly in the calldata section but will mostly ignore.) The stack and storage are made of words ("slots"), while memory, calldata, and -code are made of bytes; however, we will basically ignore this distinction. We +code are made of bytes; however, we will basically ignore this distinction. We will, for the stack and storage, conventionally consider the large end of each word to be the earlier (left) end; and, for the other locations, conventionally consider the location as divided up into words ("slots") of 32 bytes, with the -earlier end of each word being the large end. Or, in other words, everything -is big-endian (or construed as big-endian) unless stated otherwise. With this +earlier end of each word being the large end. Or, in other words, everything +is big-endian (or construed as big-endian) unless stated otherwise. With this convention, we can ignore the distinction between the slot-based locations and -the byte-based locations. (My apologies in advance for the abuse of +the byte-based locations. (My apologies in advance for the abuse of terminology that results from this, but I think using this convention here saves more trouble than it causes.) (For calldata, we will actually use a slightly different convention, as [detailed later](#user-content-locations-in-detail-calldata-in-detail-slots-in-calldata-and-the-offset), -but you can ignore that for now. We will also occasionally use a different +but you can ignore that for now. We will also occasionally use a different convention in memory, as [also detailed later](#user-content-locations-in-detail-memory-in-detail), but you can again ignore that -for now. Also, we will ignore the notion of "slots" in the case of code.) +for now. Also, we will ignore the notion of "slots" in the case of code.) Memory (with one exception to be [described later](#user-content-locations-in-detail-memory-in-detail)) and calldata will @@ -131,66 +127,68 @@ locations we'll access without a pointer (but for the stack we'll mostly rely on the debugger having other ways of determining location, and for code we'll rely on other compiler output). - ## Types Overview + [ [∧](#user-content-contents) _Back to contents_ ] -* [Terminology](#user-content-types-overview-terminology) -* [Types and locations](#user-content-types-overview-types-and-locations) - * [Table of types and locations](#user-content-types-overview-types-and-locations-table-of-types-and-locations) -* [Overview of the types: Direct types](#user-content-types-overview-overview-of-the-types-direct-types) - * [Basics of direct types: Packing and padding](#user-content-types-overview-overview-of-the-types-direct-types-basics-of-direct-types-packing-and-padding) - * [Table of direct types](#user-content-types-overview-overview-of-the-types-direct-types-table-of-direct-types) - * [Representations of direct types](#user-content-types-overview-overview-of-the-types-direct-types-representations-of-direct-types) - * [Presently unstoreable functions](#user-content-types-overview-overview-of-the-types-direct-types-presently-unstoreable-functions) -* [Overview of the types: Multivalue types](#user-content-types-overview-overview-of-the-types-multivalue-types) -* [Overview of the types: Lookup types](#user-content-types-overview-overview-of-the-types-lookup-types) - * [Table of lookup types](#user-content-types-overview-overview-of-the-types-lookup-types-table-of-lookup-types) -* [Overview of the types: Pointer types](#user-content-types-overview-overview-of-the-types-pointer-types) - * [Table of pointer types](#user-content-types-overview-overview-of-the-types-pointer-types-table-of-pointer-types) +- [Terminology](#user-content-types-overview-terminology) +- [Types and locations](#user-content-types-overview-types-and-locations) + - [Table of types and locations](#user-content-types-overview-types-and-locations-table-of-types-and-locations) +- [Overview of the types: Direct types](#user-content-types-overview-overview-of-the-types-direct-types) + - [Basics of direct types: Packing and padding](#user-content-types-overview-overview-of-the-types-direct-types-basics-of-direct-types-packing-and-padding) + - [Table of direct types](#user-content-types-overview-overview-of-the-types-direct-types-table-of-direct-types) + - [Representations of direct types](#user-content-types-overview-overview-of-the-types-direct-types-representations-of-direct-types) + - [Presently unstoreable functions](#user-content-types-overview-overview-of-the-types-direct-types-presently-unstoreable-functions) +- [Overview of the types: Multivalue types](#user-content-types-overview-overview-of-the-types-multivalue-types) +- [Overview of the types: Lookup types](#user-content-types-overview-overview-of-the-types-lookup-types) + - [Table of lookup types](#user-content-types-overview-overview-of-the-types-lookup-types-table-of-lookup-types) +- [Overview of the types: Pointer types](#user-content-types-overview-overview-of-the-types-pointer-types) + - [Table of pointer types](#user-content-types-overview-overview-of-the-types-pointer-types-table-of-pointer-types) ### Terminology + [ [∧](#user-content-types-overview) _Back to Types Overview_ ] -There are a number of ways of dividing up the types into classes. The system +There are a number of ways of dividing up the types into classes. The system I'll use here is my own, based on what I think is useful here. -A variable of *direct type* can, for our purposes, be considered as a value by itself. +A variable of _direct type_ can, for our purposes, be considered as a value by itself. -A variable of *multivalue type* holds a fixed number of other element variables, +A variable of _multivalue type_ holds a fixed number of other element variables, stored consecutively. -A variable of *lookup type* holds a number of other element variables not fixed in +A variable of _lookup type_ holds a number of other element variables not fixed in advance. -A variable of *pointer type* holds a reference to another multivalue or lookup -variable to be found elsewhere. They never point to variables of direct type or -other variables of pointer type. (Note that pointers are not, in Solidity, an +A variable of _pointer type_ holds a reference to another multivalue or lookup +variable to be found elsewhere. They never point to variables of direct type or +other variables of pointer type. (Note that pointers are not, in Solidity, an actual type separate from that of what they point to, but they're useful to consider as a separate type here.) -This will be our fourfold division of types. Some other type terminology, as +This will be our fourfold division of types. Some other type terminology, as defined by the language, is useful: -The term *reference types* refers collectively to multivalue and lookup types. +The term _reference types_ refers collectively to multivalue and lookup types. + +A _static type_ is either -A *static type* is either 1. A direct type, or 2. A multivalue type, all of whose element variables are also of static type. -(*Remark*: In pre-0.5.0 versions of Solidity, when static-length of arrays of +(_Remark_: In pre-0.5.0 versions of Solidity, when static-length of arrays of length 0 were allowed, these were automatically static regardless of the base type, since, after all, there are no element variables.) -A *dynamic type* is any type that is not static. (Pointers don't fit into this +A _dynamic type_ is any type that is not static. (Pointers don't fit into this dichotomy, not being an actual Solidity type.) -We'll also use the term *key types* to denote types that can be used as -mapping keys. See the +We'll also use the term _key types_ to denote types that can be used as +mapping keys. See the [section on lookup types](#user-content-types-overview-overview-of-the-types-lookup-types) for more on these. @@ -202,6 +200,7 @@ consistently speak of "elements" rather than "values" or "children" or ### Types and locations + [ [∧](#user-content-types-overview) _Back to Types Overview_ ] What types can go in what locations? @@ -213,15 +212,15 @@ reference type, although their elements, also living in memory or calldata, can of course also be of direct or pointer type. Some types are not allowed in calldata, especially if `ABIEncoderV2` is not -being used; but we will assume it is. Note, though, that circular types are never +being used; but we will assume it is. Note, though, that circular types are never allowed in calldata. Only direct types may go in code as immutables; moreover, variables of type -`function external` cannot presently go in code this way. (Nor can they go +`function external` cannot presently go in code this way. (Nor can they go in memory as immutables, when memory is being used to store immutables.) In addition, the locations memory and calldata may not hold mappings, which may -go only in storage. (However, structs that *contain* mappings, or that contain +go only in storage. (However, structs that _contain_ mappings, or that contain (possibly multidimensional) arrays of mappings, were allowed in memory prior to Solidity 0.7.0, though such mappings or arrrays would be omitted from the struct; see [the section on @@ -232,7 +231,7 @@ Storage does not hold pointer types as there is never any reason for it to do so. While this is not a type-level concern, it is likely worth noting here that -memory (and no other location) can contain circular structs. Storage can also +memory (and no other location) can contain circular structs. Storage can also contain structs of circular type, but not actual circular structs. Note that reference types, in Solidity, include the location as part of the type @@ -251,7 +250,7 @@ mentioned above): #### Table of types and locations | Location | Direct types | Multivalue types | Lookup types | Mappings and arrays of such in structs are... | Pointer types | -|----------|----------------------------------------------------|--------------------------------------|-------------------------|-----------------------------------------------|-----------------------------------------------| +| -------- | -------------------------------------------------- | ------------------------------------ | ----------------------- | --------------------------------------------- | --------------------------------------------- | | Stack | Yes | No (only as pointers) | No (only as pointers) | N/A | To storage, memory, or calldata | | Storage | Yes | Yes | Yes | Legal | No | | Memory | Only as elements of other types or as immutables | Yes | Yes, excluding mappings | Illegal (omitted prior to 0.7.0) | To memory (only as elements of other types) | @@ -261,12 +260,13 @@ mentioned above): Note that with the exception of the special case of mappings (or possibly multidimensional arrays of such) in structs, it is otherwise true that if the type of some element of some given type is illegal in that location, then so is -the type as a whole. Also, immutables in memory have the same restrictions that +the type as a whole. Also, immutables in memory have the same restrictions that they do in code. ### Overview of the types: Direct types + [ [∧](#user-content-types-overview) _Back to Types Overview_ ] @@ -279,12 +279,12 @@ up as much space as it need to; see the table below for information on sizes. (Note that variables of direct type may not cross word boundaries.) The stack, memory, calldata, and code, however, are padded locations -- each -variable of direct type always takes up a full slot. (There are two exceptions +variable of direct type always takes up a full slot. (There are two exceptions to this -- the individual `byte`s in a `bytes` or `string` are packed rather -than padded; and external functions take up *two* slots on the stack. Both +than padded; and external functions take up _two_ slots on the stack. Both these will be described in more detail later ([1](#user-content-locations-in-detail-memory-in-detail-memory-lookup-types), -[2](#user-content-locations-in-detail-the-stack-in-detail)).) The exact method +[2](#user-content-locations-in-detail-the-stack-in-detail)).) The exact method of padding varies by type, as detailed in [the table below](#user-content-types-overview-overview-of-the-types-direct-types-table-of-direct-types). Note that immutables have slightly unusual padding, whether stored in code or @@ -300,12 +300,12 @@ for more information.) #### Table of direct types Here is a table of all the (general classes of) direct types and their key -properties. Some of this information may not yet make sense if you have only -read up to this point. See the [next section](#user-content-types-overview-overview-of-the-types-direct-types-representations-of-direct-types) +properties. Some of this information may not yet make sense if you have only +read up to this point. See the [next section](#user-content-types-overview-overview-of-the-types-direct-types-representations-of-direct-types) for more detail on how these types are actually represented. | Type | Size in storage (bytes) | Padding in padded locations | Default value | Is key type? | Allowed in calldata? | Allowed as immutable? | Can back a UDVT? | -|--------------------------|---------------------------------------------|-------------------------------------|-------------------------------------------|--------------|----------------------|-----------------------|------------------| +| ------------------------ | ------------------------------------------- | ----------------------------------- | ----------------------------------------- | ------------ | -------------------- | --------------------- | ---------------- | | `bool` | 1 | Zero padded, left | `false` | Yes | Yes | Yes | Yes | | `uintN` | N/8 | Zero-padded, left\* | 0 | Yes | Yes | Yes | Yes | | `intN` | N/8 | Sign-padded, left\* | 0 | Yes | Yes | Yes | Yes | @@ -329,37 +329,37 @@ Some remarks: underlying type; they would be padded as if they were being stored in a padded location. 3. Prior to Solidity 0.8.9, padding worked a bit differently in code; in code, all types - were zero-padded, even if they would ordinarily be sign-padded. This did not affect + were zero-padded, even if they would ordinarily be sign-padded. This did not affect which side they are padded on. 4. Prior to Solidity 0.8.9, padding also worked a bit differently for immutables - stored in memory during contract construction. In this context, all types + stored in memory during contract construction. In this context, all types used to be zero-padded on the right, regardless of their usual padding. -5. Some types are marked with an asterisk regarding their padding. These types +5. Some types are marked with an asterisk regarding their padding. These types may have incorrect padding while on the stack due to operations that overflow. Solidity will always restore the correct padding when it is necessary to do so; - however, it will not do this *until* it is necessary to do so. So, be aware + however, it will not do this _until_ it is necessary to do so. So, be aware that on the stack these types may be padded incorrectly. -6. The `ufixedMxN` and `fixedMxN` types are not implemented yet. Their listed +6. The `ufixedMxN` and `fixedMxN` types are not implemented yet. Their listed properies are largely inferred based on what we can expect. 7. Some direct types have aliases; these have not been listed in the above table. `uint` and `int` are aliases for `uint256` and `int256`; `ufixed` and `fixed` for `ufixed128x18` and `fixed128x18`; and `byte` for `bytes1`. 8. Each direct type's default value is simply whatever value is represented by a string of all zero bytes, with the one exception of internal functions in - locations other than storage. See [below](#user-content-types-overview-overview-of-the-types-direct-types-representations-of-direct-types) for more on this. -9. The `N` in `uintN` and `intN` must be a multiple of 8, from 8 to 256. The + locations other than storage. See [below](#user-content-types-overview-overview-of-the-types-direct-types-representations-of-direct-types) for more on this. +9. The `N` in `uintN` and `intN` must be a multiple of 8, from 8 to 256. The `M` in `ufixedMxN` and `fixedMxN` must be a multiple of 8, from 8 to 256, - while `N` must be from 0 to 80. The `N` in `bytesN` must be from 1 to 32. + while `N` must be from 0 to 80. The `N` in `bytesN` must be from 1 to 32. 10. Function types are, of course, more complex than just their division into `internal` and `external`; they also have input parameter types, output parameter types, and mutability modifiers (`pure`, `view`, `payable`). However, these will not concern us here, and we will ignore them. - + #### Representations of direct types -`uintN` is an `N`-bit binary number (big-endian). The signed variant `intN` +`uintN` is an `N`-bit binary number (big-endian). The signed variant `intN` uses 2's-complement. `bytesN` is simply a string of `N` bytes. @@ -367,50 +367,52 @@ uses 2's-complement. Booleans are represented by `0` for `false` and `1` for true; they act like `uint8`, just restricted to `0` and `1`. -Addresses just act like `uint160`. Contracts are represented by their underying +Addresses just act like `uint160`. Contracts are represented by their underying addresses. Enums are represented by integers; the possibility listed first by `0`, the next -by `1`, and so forth. An enum type just acts like `uintN`, where `N` is the +by `1`, and so forth. An enum type just acts like `uintN`, where `N` is the smallest legal value large enough to accomodate all the possibilities. -Internal functions may be represented in one of two ways. The bottom 4 bytes +Internal functions may be represented in one of two ways. The bottom 4 bytes represented by the code address (in bytes from the beginning of code) of the beginning of said function (specifically, the `JUMPDEST` instruction that -begins it). If the value was set outside a constructor, the 4 bytes above that -will be 0. However, inside a constructor, the 4 bytes above that will instead +begins it). If the value was set outside a constructor, the 4 bytes above that +will be 0. However, inside a constructor, the 4 bytes above that will instead be the code address of the function inside the constructor code rather than the deployed code. For internal functions, default values are also worth discussing, as in -non-storage locations, they have a nonzero default value. In contracts for +non-storage locations, they have a nonzero default value. In contracts for which Solidity deems it necessary, there will be a special designated invalid -function. In Solidity 0.8.0 and later, this function throws a `Panic(0x51)`; +function. In Solidity 0.8.0 and later, this function throws a `Panic(0x51)`; in earlier versions of Solidity, it uses the `INVALID` opcode, reverting the transaction and consuming all available gas. In versions of Solidity prior to 0.8.0, it has the bytecode `0x5bfe`; in Solidity 0.8.0 to 0.8.4, it has the bytecode + ``` 0x5b7f000000000000000000000000000000000000000000000000000000004e487b71600052605160045260246000fd ``` + and in Solidity 0.8.5 and later, it is a function that just jumps directly to a function with the latter bytecode (this jumped-to function may also be identified by the fact that it is a generated Yul function with name `panic_error_0x51`). As mentioned, in all cases, such a function is only included if Solidity deems it necessary. The default value for an internal function, then, outside of storage, is to point to -this designated invalid function. In all other respects, these default values +this designated invalid function. In all other respects, these default values are encoded as above. -*Remark*: Prior to Solidity 0.5.8 (or Solidity 0.4.26, in the 0.4.x line) there +_Remark_: Prior to Solidity 0.5.8 (or Solidity 0.4.26, in the 0.4.x line) there was a bug causing the default value for internal functions to be incorrectly -encoded when it was set in a constructor. It would have 0 for the upper 4 +encoded when it was set in a constructor. It would have 0 for the upper 4 bytes, and would have as the lower 4 bytes what the upper 4 bytes should have been. External functions are represented by a 20-byte address and a 4-byte selector; in locations other than the stack, this consists of first the 20-byte address -and then the 4-byte selector. On the stack, however, it is more complicated. +and then the 4-byte selector. On the stack, however, it is more complicated. See the [section on the stack](#user-content-locations-in-detail-the-stack-in-detail-the-stack-direct-types-and-pointer-types) for details. `ufixedMxN` and `fixedMxN` are interpreted as follows: If interpreting as a @@ -419,7 +421,7 @@ yield `k`, the result is interpreted as the rational number `k/10**N`. User-defined value types are always backed by another type (see the [table](#user-content-types-overview-overview-of-the-types-direct-types-table-of-direct-types) -for which types are allowed in this context). Their representation is the same +for which types are allowed in this context). Their representation is the same as that of the underlying type. @@ -427,7 +429,7 @@ as that of the underlying type. #### Presently unstoreable functions Some legal values of function type presently have no representation and so -cannot be stored in a variable. These are: +cannot be stored in a variable. These are: 1. External functions with a specified amount of `gas` or `value` attached (even if that amount is zero). @@ -437,17 +439,18 @@ cannot be stored in a variable. These are: accept non-ABI types and thus have no signature according to the ABI specification. This similarly includes functions created by `using ... for ...` directives. -3. Special functions defined by the language. This means globally available +3. Special functions defined by the language. This means globally available functions; functions which are members of arrays; functions which are members of addresses; and functions which are members of external functions. So, the question of how these are presently represented when stored, is that -they are not. (There are other presently unstoreable functions, too, but since +they are not. (There are other presently unstoreable functions, too, but since their unstorability is due to other issues, we will not discuss them here.) ### Overview of the types: Multivalue types + [ [∧](#user-content-types-overview) _Back to Types Overview_ ] The multivalue types are `type[n]` (here `n` must be positive), which has `n` @@ -456,24 +459,24 @@ multiple element variables (of which there must be at least one) are as specified in the appropriate `struct` definition, and occur in the order specified there. -*Remark*: Prior to Solidity 0.5.0, it was legal to have `type[0]` or empty +_Remark_: Prior to Solidity 0.5.0, it was legal to have `type[0]` or empty structs. Note that it is legal to include a `mapping` type, or a (possibly multidimensional) array of mappings, as an element of a `struct` type; prior to -Solidity 0.7.0, this did *not* preclude the `struct` type from being used in +Solidity 0.7.0, this did _not_ preclude the `struct` type from being used in memory (even though, as per the following section, mappings cannot appear in memory), but rather, the mapping (or array) would be simply omitted in memory. See the [memory section](#user-content-locations-in-detail-memory-in-detail-memory-lookup-types) -for more details. Such a struct has always been barred from appearing in +for more details. Such a struct has always been barred from appearing in calldata, however. Also note that circular struct types are allowed, so long as the circularity is -mediated by a lookup type. That is to say, if a struct type `T0` has a element +mediated by a lookup type. That is to say, if a struct type `T0` has a element type `T1` which has a element type ... which has a element type `Tn` with `Tn` equal to T0, this is legal only if at least one of the types `Ti` is a lookup -type. However, such types are allowed only in storage and memory, not +type. However, such types are allowed only in storage and memory, not calldata. The default value for a multivalue type consists of assigning the default value @@ -484,6 +487,7 @@ to each of its element variables. ### Overview of the types: Lookup types + [ [∧](#user-content-types-overview) _Back to Types Overview_ ] The lookup types are `type[]`; `mapping(keyType => elementType)`; `bytes`; and @@ -491,12 +495,12 @@ The lookup types are `type[]`; `mapping(keyType => elementType)`; `bytes`; and Dynamic arrays, `type[]`, have an indefinite number of elements of type `type`. Mappings, `mapping(keyType => elementType`, have an indefinite number of -elements of type `elementType`. Bytestrings, `bytes`, have an indefinite number +elements of type `elementType`. Bytestrings, `bytes`, have an indefinite number of elements of type `byte`. The type `string` is something of a special case; strings are UTF-8 encoded to form a string of bytes, and then that string of bytes is stored exactly as if it -were a `bytes`. For this reason, we will basically ignore the type `string` +were a `bytes`. For this reason, we will basically ignore the type `string` from here on out; it basically acts exactly like `bytes`, except that one cannot meaningfully speak of its elements. @@ -509,7 +513,7 @@ the appropriate tables to see which [direct](#user-content-types-overview-overvi Observe that key types may all be meaningfully converted to a string of bytes. -The default value for a lookup type is for it to be empty. For the particular +The default value for a lookup type is for it to be empty. For the particular case of a `type[]` in memory, the default value once it has been initialized to a particular size is for all its elements to have their default value. @@ -520,7 +524,7 @@ The information above is also summarized in the following table. #### Table of lookup types | Type | Element type | Restricted to storage? | Is key type? | -|-----------------------------------|-------------------------------------------------|------------------------|--------------| +| --------------------------------- | ----------------------------------------------- | ---------------------- | ------------ | | `type[]` | `type` | No | No | | `mapping(keyType => elementType)` | `elementType` | Yes | No | | `bytes` | `byte` (`bytes1`) | No | Yes | @@ -532,6 +536,7 @@ deleted -- but we will not go into that here. ### Overview of the types: Pointer types + [ [∧](#user-content-types-overview) _Back to Types Overview_ ] Pointers usually take up a single word, although some take up two words. See the @@ -546,18 +551,18 @@ that of what they point to, but we're considering them here separately all the same. Pointers always either point from the stack to somewhere else, or from one -location to somewhere else in that same location. Pointers never go between +location to somewhere else in that same location. Pointers never go between different non-stack locations. The default value for a memory pointer to a variable of lookup type is `0x60`, the null pointer; see the [section on memory pointers](#user-content-locations-in-detail-memory-in-detail-pointers-to-memory) for -more information. Attempting to delete a memory pointer to a variable of +more information. Attempting to delete a memory pointer to a variable of multivalue type instead allocates a new instance of that type, of its default value, and sets the pointer to point at this, so memory pointers to variables of multivalue type have no fixed default value. The default value for a storage pointer is a pointer to the `0` slot -- beware, -making use of such a pointer *can* lead to nonsense! Don't do this! (Note that +making use of such a pointer _can_ lead to nonsense! Don't do this! (Note that while it is legal to leave a storage pointer uninitialized, it is not legal to delete one.) @@ -568,50 +573,51 @@ it's illegal to delete them. #### Table of pointer types -| Type | Absolute or relative? | Measured in... | Has second word for length? | Default value | -|------------------------------------------------------|------------------------------|----------------|-----------------------------|----------------------------------------------------------------| -| Pointer to storage | Absolute | Words | No | `0` (may be garbage, don't use!) | -| Pointer to memory | Absolute | Bytes | No | `0x60` for lookup types; no fixed default for multivalue types | -| Pointer to calldata from calldata | Relative (in an unusual way) | Bytes | No | N/A | -| Pointer to calldata multivalue type from the stack | Absolute | Bytes | No | Equal to the length of calldata | -| Pointer to calldata lookup type from the stack | Absolute (with an offset) | Bytes | Yes | Equal to the length of calldata; length word equal to zero | - +| Type | Absolute or relative? | Measured in... | Has second word for length? | Default value | +| -------------------------------------------------- | ---------------------------- | -------------- | --------------------------- | -------------------------------------------------------------- | +| Pointer to storage | Absolute | Words | No | `0` (may be garbage, don't use!) | +| Pointer to memory | Absolute | Bytes | No | `0x60` for lookup types; no fixed default for multivalue types | +| Pointer to calldata from calldata | Relative (in an unusual way) | Bytes | No | N/A | +| Pointer to calldata multivalue type from the stack | Absolute | Bytes | No | Equal to the length of calldata | +| Pointer to calldata lookup type from the stack | Absolute (with an offset) | Bytes | Yes | Equal to the length of calldata; length word equal to zero | ## Locations in Detail + [ [∧](#user-content-contents) _Back to contents_ ] -* [The stack in detail](#user-content-locations-in-detail-the-stack-in-detail) - * [The stack: Direct types and pointer types](#user-content-locations-in-detail-the-stack-in-detail-the-stack-direct-types-and-pointer-types) - * [The stack: Data layout](#user-content-locations-in-detail-the-stack-in-detail-the-stack-data-layout) -* [Code in detail](#user-content-locations-in-detail-code-in-detail) - * [Code: direct types](#user-content-locations-in-detail-code-in-detail-code-direct-types) - * [Code: data layout](#user-content-locations-in-detail-code-in-detail-code-data-layout) -* [Memory in detail](#user-content-locations-in-detail-memory-in-detail) - * [Memory: Direct types and pointer types](#user-content-locations-in-detail-memory-in-detail-memory-direct-types-and-pointer-types) - * [Layout of immutables in memory](#user-content-locations-in-detail-memory-in-detail-layout-of-immutables-in-memory) - * [Memory: Multivalue types](#user-content-locations-in-detail-memory-in-detail-memory-multivalue-types) - * [Memory: Lookup types](#user-content-locations-in-detail-memory-in-detail-memory-lookup-types) - * [Pointers to memory](#user-content-locations-in-detail-memory-in-detail-pointers-to-memory) -* [Calldata in detail](#user-content-locations-in-detail-calldata-in-detail) - * [Slots in calldata and the offset](#user-content-locations-in-detail-calldata-in-detail-slots-in-calldata-and-the-offset) - * [Calldata: Direct types and pointer types](#user-content-locations-in-detail-calldata-in-detail-calldata-direct-types-and-pointer-types) - * [Calldata: Multivalue and lookup types (reference types)](#user-content-locations-in-detail-calldata-in-detail-calldata-multivalue-and-lookup-types-reference-types) - * [The special variable `msg.data`](#user-content-locations-in-detail-calldata-in-detail-calldata-multivalue-and-lookup-types-reference-types-the-special-variable-msg-data) - * [Pointers to calldata](#user-content-locations-in-detail-calldata-in-detail-pointers-to-calldata) - * [Pointers to calldata from calldata](#user-content-locations-in-detail-calldata-in-detail-pointers-to-calldata-from-calldata) - * [Pointers to calldata from the stack](#user-content-locations-in-detail-calldata-in-detail-pointers-to-calldata-from-the-stack) -* [Storage in detail](#user-content-locations-in-detail-storage-in-detail) - * [Storage: Data layout](#user-content-locations-in-detail-storage-in-detail-storage-data-layout) - * [Storage: Direct types](#user-content-locations-in-detail-storage-in-detail-storage-direct-types) - * [Storage: Multivalue types](#user-content-locations-in-detail-storage-in-detail-storage-multivalue-types) - * [Storage: Lookup types](#user-content-locations-in-detail-storage-in-detail-storage-lookup-types) - * [Pointers to storage](#user-content-locations-in-detail-storage-in-detail-pointers-to-storage) +- [The stack in detail](#user-content-locations-in-detail-the-stack-in-detail) + - [The stack: Direct types and pointer types](#user-content-locations-in-detail-the-stack-in-detail-the-stack-direct-types-and-pointer-types) + - [The stack: Data layout](#user-content-locations-in-detail-the-stack-in-detail-the-stack-data-layout) +- [Code in detail](#user-content-locations-in-detail-code-in-detail) + - [Code: direct types](#user-content-locations-in-detail-code-in-detail-code-direct-types) + - [Code: data layout](#user-content-locations-in-detail-code-in-detail-code-data-layout) +- [Memory in detail](#user-content-locations-in-detail-memory-in-detail) + - [Memory: Direct types and pointer types](#user-content-locations-in-detail-memory-in-detail-memory-direct-types-and-pointer-types) + - [Layout of immutables in memory](#user-content-locations-in-detail-memory-in-detail-layout-of-immutables-in-memory) + - [Memory: Multivalue types](#user-content-locations-in-detail-memory-in-detail-memory-multivalue-types) + - [Memory: Lookup types](#user-content-locations-in-detail-memory-in-detail-memory-lookup-types) + - [Pointers to memory](#user-content-locations-in-detail-memory-in-detail-pointers-to-memory) +- [Calldata in detail](#user-content-locations-in-detail-calldata-in-detail) + - [Slots in calldata and the offset](#user-content-locations-in-detail-calldata-in-detail-slots-in-calldata-and-the-offset) + - [Calldata: Direct types and pointer types](#user-content-locations-in-detail-calldata-in-detail-calldata-direct-types-and-pointer-types) + - [Calldata: Multivalue and lookup types (reference types)](#user-content-locations-in-detail-calldata-in-detail-calldata-multivalue-and-lookup-types-reference-types) + - [The special variable `msg.data`](#user-content-locations-in-detail-calldata-in-detail-calldata-multivalue-and-lookup-types-reference-types-the-special-variable-msg-data) + - [Pointers to calldata](#user-content-locations-in-detail-calldata-in-detail-pointers-to-calldata) + - [Pointers to calldata from calldata](#user-content-locations-in-detail-calldata-in-detail-pointers-to-calldata-from-calldata) + - [Pointers to calldata from the stack](#user-content-locations-in-detail-calldata-in-detail-pointers-to-calldata-from-the-stack) +- [Storage in detail](#user-content-locations-in-detail-storage-in-detail) + - [Storage: Data layout](#user-content-locations-in-detail-storage-in-detail-storage-data-layout) + - [Storage: Direct types](#user-content-locations-in-detail-storage-in-detail-storage-direct-types) + - [Storage: Multivalue types](#user-content-locations-in-detail-storage-in-detail-storage-multivalue-types) + - [Storage: Lookup types](#user-content-locations-in-detail-storage-in-detail-storage-lookup-types) + - [Pointers to storage](#user-content-locations-in-detail-storage-in-detail-pointers-to-storage) ### The stack in detail + [ [∧](#user-content-locations-in-detail) _Back to Locations in Detail_ ] The stack, as [mentioned above](#user-content-types-overview-types-and-locations), can hold only direct types and pointer types. @@ -629,10 +635,10 @@ padded to a full word in the manner described in the [direct types table](#user-content-types-overview-overview-of-the-types-direct-types-table-of-direct-types). There are two special cases that must be noted here, that each take up two words -instead of one. The first special case is that of external functions. An +instead of one. The first special case is that of external functions. An external function is represented by a 20-byte address and a 4-byte selector; these are stored in two separate words, with the address in the bottom word and -the selector in the top word. Both these are zero-padded on the *left*, not the +the selector in the top word. Both these are zero-padded on the _left_, not the right [like in the other padded locations](#user-content-types-overview-overview-of-the-types-direct-types-table-of-direct-types). The second two-word special case is that of pointers to calldata lookup types; @@ -644,21 +650,21 @@ stack](#user-content-locations-in-detail-calldata-in-detail-pointers-to-calldata #### The stack: Data layout Stack variables are local variables, so naturally things will change as the -contract executes. But, we can still describe how things are at any given -time. Note that if you are actually writing a debugger, you may want to rely +contract executes. But, we can still describe how things are at any given +time. Note that if you are actually writing a debugger, you may want to rely on other systems to determine data layout on the stack. The stack is of course not used only for storing local variables, but also as a -working space. And of course it also holds return addresses. The stack is +working space. And of course it also holds return addresses. The stack is divided into stackframes; each stackframe begins with the return address. (There is no frame pointer, for those used to such a thing; just a return -address.) The exceptions are constructors and fallback/receive functions, which do not -include a return address. In addition, if the initial function call (i.e. +address.) The exceptions are constructors and fallback/receive functions, which do not +include a return address. In addition, if the initial function call (i.e. stackframe) of the EVM stackframe (i.e. message call or creation call) is not a constructor, and the contract has external functions other than the constructor, fallback, and receive functions, then the function selector will be stored on the stack below the first -stackframe. (Additionally, in Solidity 0.4.20 and later, an extra zero word +stackframe. (Additionally, in Solidity 0.4.20 and later, an extra zero word will appear below that on the stack if you're within a library call, unless the function called is `pure` or `view` and does not include any storage pointers in its input or output parameters.) @@ -669,68 +675,69 @@ part of the same stackframe as the function that invoked them. Within each stackframe, all variables are always stored below the workspace. So while the workspace may be unpredictable, we can ignore it for the purposes of -data layout within a given stackframe. (Of course, the workspace in one +data layout within a given stackframe. (Of course, the workspace in one stackframe does come between that stackframe's variables and the start of the next stackframe.) Restricting our attention to the variables, then, the stack acts, as expected, as a stack; variables are pushed onto it when needed, and are popped off of it -when no longer needed. These pushes and pops are arranged in a way that is +when no longer needed. These pushes and pops are arranged in a way that is compatible with the stack structure; i.e., they are in fact pushes and pops. The parameters of the function being called, including output parameters, are pushed onto the stack when the function is called and the stackframe is -entered, and are not popped until the function, *including all modifiers*, -exits. It's necessary here to specify the order they go onto the stack. First +entered, and are not popped until the function, _including all modifiers_, +exits. It's necessary here to specify the order they go onto the stack. First come the input parameters, in the order they were given, followed by the output -parameters, in the order they were given. Anonymous output parameters are -treated the same as named output parameters for these purposes. Similarly, +parameters, in the order they were given. Anonymous output parameters are +treated the same as named output parameters for these purposes. Similarly, parameters for fallback functions are not treated specially here, but work like any other parameters. -*Remark*: Yul functions work slightly differently here, in that output parameters -are pushed onto the stack in the *reverse* of the order they were given. +_Remark_: Yul functions work slightly differently here, in that output parameters +are pushed onto the stack in the _reverse_ of the order they were given. Ordinary local variables, as declared in a function or modifier, are pushed onto the stack at their declaration and are popped when their containing block exits (for variables declared in the initializer of a `for` loop, the -containing block is considered to be the `for` loop). If multiple variables +containing block is considered to be the `for` loop). If multiple variables are declared within a single statement, they go on the stack in the order they were declared within that statement. Parameters to a modifier are pushed onto the stack when that modifier begins -and are popped when that modifier exits. Again, they go in the stack in the -order they were given. Note that (like other local variables declared in +and are popped when that modifier exits. Again, they go in the stack in the +order they were given. Note that (like other local variables declared in modifiers) these variables are still on the stack while the placeholder -statement `_;` is running, even if they are inaccessible. Remember that +statement `_;` is running, even if they are inaccessible. Remember that modifiers are run in order from left to right, and that they may be applied to constructors, fallback functions, and receive functions. This leaves the case of parameters to base constructor invocations (whether on -the constructor or on the contract). When a constructor is called, not only +the constructor or on the contract). When a constructor is called, not only are its parameters pushed onto the stack, but so are all the parameters to all of its base constructors -- not just the direct parents, but for all ancestors. They go on in order from most derived to most base, as determined by the usual [C3 order](https://en.wikipedia.org/wiki/C3_linearization) -(discussed more in the [section on storage layout below](#user-content-locations-in-detail-storage-in-detail-storage-data-layout)). Note that if +(discussed more in the [section on storage layout below](#user-content-locations-in-detail-storage-in-detail-storage-data-layout)). Note that if the base constructors are listed on the constructor declaration, the order has no effect; only the order that the base classes are listed on the class -declaration matters here. Within each base constructor's parameter region, the -parameters are pushed on in order from left to right. Constructors then +declaration matters here. Within each base constructor's parameter region, the +parameters are pushed on in order from left to right. Constructors then execute in order from most base to most derived (again, note that the order they're listed on the constructor declaration has no effect); when a -constructor exits, its parameters are popped from the stack. Modifiers on a +constructor exits, its parameters are popped from the stack. Modifiers on a constructor or base constructor are handled when that constructor or base constructor runs. Paramters to a modifier on a fallback or receive function work like parameters -to a modifier on any other function. Note that parameters to a modifier on a +to a modifier on any other function. Note that parameters to a modifier on a constructor only go onto the stack when that particular constructor is about to run (i.e., all base constructors that run before it have exited). ### Code in detail + [ [∧](#user-content-locations-in-detail) _Back to Locations in Detail_ ] Once a contract has been deployed, its immutable state variables are stored in its code. @@ -739,13 +746,13 @@ Once a contract has been deployed, its immutable state variables are stored in i #### Code: direct types -Only direct types may go in code as immutables. In addition, `function external` +Only direct types may go in code as immutables. In addition, `function external` variables are currently barred from being used as immutables. Note that while code is a padded location, prior to Solidity 0.8.9, its padding -worked a bit unusually. In code, all types would be zero-padded, even if -ordinarily they would be sign-padded. Note that this did not alter whether -they are padded on the right or on the left. Since Solidity 0.8.9, however, +worked a bit unusually. In code, all types would be zero-padded, even if +ordinarily they would be sign-padded. Note that this did not alter whether +they are padded on the right or on the left. Since Solidity 0.8.9, however, types in code are just padded normally. @@ -753,10 +760,10 @@ types in code are just padded normally. #### Code: data layout Where in the code immutables may be found is basically unpredictable in -advance. However, you may use the Solidity compiler's `immutableReferences` -output to determine this information. Note that immutables that are never +advance. However, you may use the Solidity compiler's `immutableReferences` +output to determine this information. Note that immutables that are never actually read from will not appear here -- as they won't actually appear -anywhere in the code, either! Immutables are simply inlined into the code +anywhere in the code, either! Immutables are simply inlined into the code wherever they're read from, so if they're never read from, their value isn't actually stored anywhere. @@ -766,22 +773,23 @@ the compiler places them, among the code. ### Memory in detail + [ [∧](#user-content-locations-in-detail) _Back to Locations in Detail_ ] -Memory is used in two different ways. Its ordinary use is to hold variables -declared as living in memory. Its secondary use, however, is to hold +Memory is used in two different ways. Its ordinary use is to hold variables +declared as living in memory. Its secondary use, however, is to hold immutables during contract construction. We won't discuss layout in memory in the first context, since, as mentioned, we -only access it via pointers. However, we will discuss layout in memory for the +only access it via pointers. However, we will discuss layout in memory for the case of immutables in memory. -*Remark*: Although memory objects ordinarily start on a word, there is a bug in +_Remark_: Although memory objects ordinarily start on a word, there is a bug in versions 0.5.3, 0.5.5, and 0.5.6 of Solidity specifically that can occasionally cause them to -start in the middle of a word. In this case, for the purposes of decoding that +start in the middle of a word. In this case, for the purposes of decoding that object, you should consider slots to begin at the beginning of that object. (Of course, once you follow a pointer, you'll have to have your slots based on that -pointer. Again, since we only access memory through pointers, this is mostly +pointer. Again, since we only access memory through pointers, this is mostly not a concern, and it only happens at all in those specific versions of Solidity.) @@ -794,9 +802,9 @@ Pointers, as mentioned above, always take up a full word. **Note that prior to Solidity 0.8.9**, immutables stored in memory had unusual padding; they were always zero-padded on the right, regardless of their usual -padding. Again, note that this only applied to immutables stored directly in +padding. Again, note that this only applied to immutables stored directly in memory during contract construct, and not to direct types appearing as elements -of another type in memory in memory's normal use. Since Solidity 0.8.9, all +of another type in memory in memory's normal use. Since Solidity 0.8.9, all direct types stored in memory, including immutables, have had normal padding. @@ -809,21 +817,21 @@ will be overwritten by the code of the contract being constructed.) Immutable state variables are stored one after the other starting at memory address `0x80` (skipping the first four words of memory as Solidity reserves -these for internal purposes). Memory being a padded location, each takes up +these for internal purposes). Memory being a padded location, each takes up one word (although note that as per the [previous subsection](#user-content-locations-in-detail-memory-in-detail-memory-direct-types-and-pointer-types), -the padding on immutables was unusual prior to Solidity 0.8.9). This just leaves the question of the +the padding on immutables was unusual prior to Solidity 0.8.9). This just leaves the question of the order that they are stored in. For the simple case of a contract without inheritance, the immutable state -variables are stored in the order that they are declared. In the case of +variables are stored in the order that they are declared. In the case of inheritance, the variables of the base class go before those of the derived -class. In cases of multiple inheritance, Solidity uses the [C3 +class. In cases of multiple inheritance, Solidity uses the [C3 linearization](https://en.wikipedia.org/wiki/C3_linearization) to order classes from "most base" to "most derived", and then, as mentioned above, lays out variables starting with the most base and ending with the most derived. (Remember that, when listing parent classes, Solidity considers parents listed -*first* to be "more base"; as the [Solidity docs +_first_ to be "more base"; as the [Solidity docs note](https://docs.soliditylang.org/en/v0.8.9/contracts.html#multiple-inheritance-and-linearization), this is the reverse order from, say, Python.) @@ -840,20 +848,20 @@ pointers](#user-content-locations-in-detail-memory-in-detail-pointers-to-memory) (possibly multidimensional) arrays of such, were allowed in memory structs and were simply omitted, as mappings cannot appear in memory.) As such, each element (that isn't omitted) takes up exactly one word (because direct types -are padded and all reference types are stored as pointers). Elements of +are padded and all reference types are stored as pointers). Elements of structs go in the order they're specified in. (Note that prior to Solidity 0.7.0 it was possible to have in memory a struct -that contains *only* mappings, and prior to 0.5.0, it was possible to have a -struct that was empty entirely, or a statically-sized array of length 0. Such +that contains _only_ mappings, and prior to 0.5.0, it was possible to have a +struct that was empty entirely, or a statically-sized array of length 0. Such a struct or array doesn't really have a representation in memory, since in -memory it has zero length. Of course, since we only access memory through +memory it has zero length. Of course, since we only access memory through pointers, if we are given a pointer to such a struct or array, we need not -decode anything, as all of the struct's elements have been omitted. The actual +decode anything, as all of the struct's elements have been omitted. The actual location pointed to may contain junk and should be ignored.) Note that it is possible to have circular structs -- not just circular struct -types, but actual circular structs -- in memory. This is not possible in any +types, but actual circular structs -- in memory. This is not possible in any other location. @@ -871,32 +879,32 @@ above](#user-content-locations-in-detail-memory-in-detail-memory-multivalue-type A `bytes` is represented by a slot containing the length of the bytestring, followed by a sequence of slots containing the bytestring; the bytes in the -string are *not* individually padded, but rather are simply stored in sequence. +string are _not_ individually padded, but rather are simply stored in sequence. Since the last slot may not contain a full 32 bytes, it is zero-padded on the right. -*Remark*: In a few specific versions of Solidity, there is a bug that can cause +_Remark_: In a few specific versions of Solidity, there is a bug that can cause particular `bytes` and `string`s to lack the padding on the end, resulting in the alignment bug [mentioned above](#user-content-locations-in-detail-memory-in-detail). - #### Pointers to memory -Pointers to memory are absolute and given in bytes. Since memory is padded, all +Pointers to memory are absolute and given in bytes. Since memory is padded, all pointers will point to the start of a word and thus be a multiple of `0x20`. (With the exception, [mentioned above](#user-content-locations-in-detail-memory-in-detail), of some pointers in some specific versions of Solidity.) The pointer `0x60` is something of a null pointer; it points to a reserved slot -which is always zero. By the previous section, this slot can therefore +which is always zero. By the previous section, this slot can therefore represent any empty variable of lookup type in memory, and in fact it's used as a default value for memory pointers of lookup type. ### Calldata in detail + [ [∧](#user-content-locations-in-detail) _Back to Locations in Detail_ ] Calldata is largely the same as [memory](#user-content-locations-in-detail-memory-in-detail); so rather than @@ -905,8 +913,8 @@ memory. Importantly, we will use a different convention when talking about "slots" in calldata; see the [following subsection](#user-content-locations-in-detail-calldata-in-detail-slots-in-calldata-and-the-offset). -(Although it's not *that* important, since, like with memory, we only access -calldata through pointers. You just don't want to find yourself surprised by +(Although it's not _that_ important, since, like with memory, we only access +calldata through pointers. You just don't want to find yourself surprised by it.) @@ -914,10 +922,10 @@ it.) #### Slots in calldata and the offset The first four bytes of calldata are the function selector, and are not followed -by any padding. As such, in calldata, we consider words and slots to begin not +by any padding. As such, in calldata, we consider words and slots to begin not on the [usual word boundaries](#user-content-locations-basics) (multiples of `0x20`) but rather to begin offset by 4-bytes; "slots" in calldata will begin at bytes whose -address is congruent to `0x4` modulo `0x20`. (Since calldata is byte-based +address is congruent to `0x4` modulo `0x20`. (Since calldata is byte-based rather than word-based, this offset is not disastrous like it would be in, say, storage.) @@ -926,7 +934,7 @@ relevant, but it is worth noting. Also note that in constructors, there is no 4-byte offset, but that's because in constructors, calldata is empty (the special variable `msg.sig` is padded to -contain 4 zero bytes). Parameters passed to constructors actually go in *code* +contain 4 zero bytes). Parameters passed to constructors actually go in _code_ rather than calldata -- and are represented the same way but with a different offset -- but since we will only deal with them once they have been copied onto the stack or into memory, we will ignore this. @@ -946,20 +954,20 @@ but you can see below about that. #### Calldata: Multivalue and lookup types (reference types) In order to understand reference types in calldata, we need the distinction of -*static* and *dynamic* types that was [introduced earlier](#user-content-types-overview-terminology). +_static_ and _dynamic_ types that was [introduced earlier](#user-content-types-overview-terminology). With that in hand, then, variables of reference type in calldata are stored similarly to in memory ([1](#user-content-locations-in-detail-memory-in-detail-memory-multivalue-types), [2](#user-content-locations-in-detail-memory-in-detail-memory-lookup-types)), with the difference that any of their elements of -static reference type are *not* stored as pointers, but are simply stored -inline; so unlike in memory, elements may take up multiple words. Elements of +static reference type are _not_ stored as pointers, but are simply stored +inline; so unlike in memory, elements may take up multiple words. Elements of dynamic type are still stored as pointers (but see the [section below](#user-content-locations-in-detail-calldata-in-detail-pointers-to-calldata) about how those work). Also, structs that contain mappings (or arrays of such) are entirely illegal in calldata, unlike in memory where the mappings are simply omitted. -*Remark*: Calldata variables were only introduced in Solidity 0.5.0, so it is +_Remark_: Calldata variables were only introduced in Solidity 0.5.0, so it is impossible to have variables of zero-element multivalue type in calldata; however, it still may be worth noting for other purposes that in the underlying encoding, such variables are omitted entirely in calldata (unlike in storage @@ -971,15 +979,15 @@ where they still take up a single word, or memory where it varies). While I've thus far avoided discussing special variables, it's worth pausing here to discuss the special variable `msg.data`, the one special variable of -reference type. It is a `bytes calldata`. But it's not represented like other -variables of type `bytes calldata`, is it? It's not some location in calldata -with the number of bytes followed by the string of bytes; it simply *is* all of -calldata. Accesses to it are simply accesses to the string of bytes that is +reference type. It is a `bytes calldata`. But it's not represented like other +variables of type `bytes calldata`, is it? It's not some location in calldata +with the number of bytes followed by the string of bytes; it simply _is_ all of +calldata. Accesses to it are simply accesses to the string of bytes that is calldata. This raises the question: Given that calldata is of variable length, where is -the length of `msg.data` stored? The answer, of course, is that this length is -what is returned by the `CALLDATASIZE` instruction. This instruction could be +the length of `msg.data` stored? The answer, of course, is that this length is +what is returned by the `CALLDATASIZE` instruction. This instruction could be considered something of a special location, and indeed many of the Solidity language's special [globally available variables](https://docs.soliditylang.org/en/v0.8.9/units-and-global-variables.html) @@ -992,7 +1000,7 @@ are all of type `uint256`, `address`, or `address payable`; these special locati word-based rather than byte-based (to the extent that distinction is meaningful here); and values from these special locations will always be copied to the (also word-based) stack before use, there is little to say about encoding in -these special locations. One could say that addresses are, as always, +these special locations. One could say that addresses are, as always, zero-padded on the left, and that integers are, as always, stored in binary; and these statements would be true in a sense, but also largely meaningless. @@ -1018,7 +1026,7 @@ single null location like in memory.) #### Pointers to calldata from calldata Pointers to calldata from calldata are relative, though in a slightly unusual -manner. They are also given in bytes, but are relative not to the current +manner. They are also given in bytes, but are relative not to the current location, but rather to the [structure they are a part of](#user-content-locations-in-detail-calldata-in-detail-calldata-multivalue-and-lookup-types-reference-types) (since they never stand alone.) @@ -1027,7 +1035,7 @@ For pointers to calldata stored in variables of multivalue type, the pointer is relative to the start of that containing variable. For pointers to calldata stored in variables of lookup type, the pointer is -relative to the start of the list of elements, i.e., the word *after* the length. +relative to the start of the list of elements, i.e., the word _after_ the length. Or, to put it differently, either way it is always relative to the start of the list of elements it is contained in. @@ -1042,24 +1050,24 @@ than absolute). Pointers to a calldata multivalue types from the stack work just like [pointers to memory](#user-content-locations-in-detail-pointers-to-memory): They are -absolute, given in bytes, and always point to the start of a word. In +absolute, given in bytes, and always point to the start of a word. In calldata, though, the [start of a word](#user-content-locations-in-detail-calldata-in-detail-slots-in-calldata-and-the-offset) is congruent to `0x4` modulo `0x20`, rather than being a multiple of `0x20`. Pointers to calldata lookup types from the stack take up two words on the stack -rather than just one. The bottom word is a pointer -- absolute and given in +rather than just one. The bottom word is a pointer -- absolute and given in bytes -- but points not to the word containing the length, but rather the start of the content, i.e., the word after the length (as described in the section on [lookup types in memory](#user-content-locations-in-detail-memory-in-detail-memory-lookup-types)), since [lookup types in calldata](#user-content-locations-in-detail-calldata-in-detail-calldata-multivalue-and-lookup-types-reference-types) are -similar). The top word contains the length. Note, obviously, that if the length is +similar). The top word contains the length. Note, obviously, that if the length is zero then the value of the pointer is irrelevant (and the word it points to may contain unrelated data). - ### Storage in detail + [ [∧](#user-content-locations-in-detail) _Back to Locations in Detail_ ] Storage, unlike the other locations mentioned thus far, is a @@ -1076,17 +1084,17 @@ data layout in storage. #### Storage: Data layout Storage is used to hold all state variables that are not declared `constant` or -`immutable`. In what follows, we ignore `constant` and `immutable` variables, -and look just at the ordinary state variables. (Variables declared `constant` +`immutable`. In what follows, we ignore `constant` and `immutable` variables, +and look just at the ordinary state variables. (Variables declared `constant` are optimized out by the compiler; variables declared `immutable` are stored in [code](#user-content-locations-in-detail-code-in-detail-code-data-layout) or [memory](#user-content-locations-in-detail-memory-in-detail-layout-of-immutables-in-memory) instead.) First, we consider the case of a contract that does not inherit from any others. In this case, state variables in storage are always laid out in the order that they were declared, -starting from the beginning of storage. However, within a word, variables are -laid out from *right to left*, not left to right (with one sort-of-exception to -be [described later](#user-content-locations-in-detail-storage-in-detail-storage-lookup-types)). Variables of direct type may not +starting from the beginning of storage. However, within a word, variables are +laid out from _right to left_, not left to right (with one sort-of-exception to +be [described later](#user-content-locations-in-detail-storage-in-detail-storage-lookup-types)). Variables of direct type may not cross a word boundary; if there is not enough room left at the top of a word for what comes next, the unused space at the top of the word remains filled with zeroes, and the next variable starts at the bottom of the next word. @@ -1110,7 +1118,7 @@ possible. Now, we consider inheritance. In cases of inheritance, the variables of the base class go before those of the -derived class. Note that there is *not* any sort of barrier between the +derived class. Note that there is _not_ any sort of barrier between the variables of the base class and those of the derived class; variables of the base class and variables of the derived class may share a slot (so the first variable of the derived class need not start on a slot boundary). @@ -1120,7 +1128,7 @@ linearization](https://en.wikipedia.org/wiki/C3_linearization) to order classes from "most base" to "most derived", and then, as mentioned above, lays out variables starting with the most base and ending with the most derived. (Remember that, when listing parent classes, Solidity considers parents listed -*first* to be "more base"; as the [Solidity docs +_first_ to be "more base"; as the [Solidity docs note](https://docs.soliditylang.org/en/v0.8.9/contracts.html#multiple-inheritance-and-linearization), this is the reverse order from, say, Python.) @@ -1130,7 +1138,7 @@ this is the reverse order from, say, Python.) The layout of direct types has already been described [above](#user-content-locations-in-detail-storage-in-detail-storage-data-layout), and the sizes of the direct types are found in the -[direct types table](#user-content-types-overview-overview-of-the-types-direct-types-table-of-direct-types). Note that there are [no pointer +[direct types table](#user-content-types-overview-overview-of-the-types-direct-types-table-of-direct-types). Note that there are [no pointer types in storage](#user-content-types-overview-overview-of-the-types-pointer-types). **Note that in Solidity 0.8.8**, there was a bug that caused user-defined value @@ -1143,18 +1151,18 @@ underlying type; values of these types would be padded as normal. Variables of multivalue type simply have the elements stored consecutively within storage -- they are packed within the multivalue type [just as variables -are packed within storage](#user-content-locations-in-detail-storage-in-detail-storage-data-layout). The rules are exactly the same. +are packed within storage](#user-content-locations-in-detail-storage-in-detail-storage-data-layout). The rules are exactly the same. The one exceptions is that (in pre-0.5.0 versions of Solidity where this was legal) multivalue types with zero elements still take up a single word, rather -than zero words. (So, for instance, a `uint[2][0]` takes up 1 word, and a +than zero words. (So, for instance, a `uint[2][0]` takes up 1 word, and a `bytes1[0][3]` takes up 3 words.) Again, remember that variables of multivalue type must occupy whole words; they start on a word boundary, and whatever comes after starts on a word boundary -too. And, obviously, this applies to variables of multivalue type *within* +too. And, obviously, this applies to variables of multivalue type _within_ another variable of multivalue type since, as mentioned, the rules are exactly -the same. (But I thought that case was worth highlighting.) +the same. (But I thought that case was worth highlighting.) @@ -1162,38 +1170,37 @@ the same. (But I thought that case was worth highlighting.) There are three lookup types that can go in storage: `type[]`, `bytes` (and `string`, but [again we will not treat that -separately](#user-content-types-overview-overview-of-the-types-lookup-types)), and `mapping(keyType => -elementType)`. +separately](#user-content-types-overview-overview-of-the-types-lookup-types)), and `mapping(keyType => elementType)`. As [mentioned above](#user-content-locations-in-detail-storage-in-detail-storage-data-layout), we regard each lookup type as taking up one word; we will call this the "main word". For `type[]`, i.e. an array, the main word contains the length of the array. -Suppose the main word is in slot `p` and the length it contains is `n`. Then +Suppose the main word is in slot `p` and the length it contains is `n`. Then the array itself is stored exactly as if it were an array of type `type[n]` ([see section above](#user-content-locations-in-detail-storage-in-detail-storage-multivalue-types)), except that it starts in the slot `keccak256(p)`. -(Yes, that is the *position* being used; no explicit pointer to the array -location is stored. Other lookup types will be similar in this regard.) +(Yes, that is the _position_ being used; no explicit pointer to the array +location is stored. Other lookup types will be similar in this regard.) For `bytes`, if the length (call it `n`) is less than 32, the low byte of the main word contains `n<<1`, and the string of bytes itself is stored in the same -word, in sequence from *left to right*; any unused space within the word is left +word, in sequence from _left to right_; any unused space within the word is left as zero. If, on the other hand, the length `n` is at least 32, then the low byte of the main word contains `(n<<1)|0x1`, and the string of bytes is stored starting in -the slot `keccak256(p)`, where `p` is the position of the main word. This -bytestring, too, goes from *left to right* within words, but (like an array) can -take up as many words as necessary. Again, any unused space left within the +the slot `keccak256(p)`, where `p` is the position of the main word. This +bytestring, too, goes from _left to right_ within words, but (like an array) can +take up as many words as necessary. Again, any unused space left within the last word is left as zero. (Type `bytes` (and `string`) is the one sort-of-exception I mentioned to the [right-to-left rule within storage](#user-content-locations-in-detail-storage-in-detail-storage-data-layout).) -Finally, we have mappings. For mappings, the main word itself is unused and -left as zero; only its position `p` is used. Mappings, famously, do not store +Finally, we have mappings. For mappings, the main word itself is unused and +left as zero; only its position `p` is used. Mappings, famously, do not store what keys exist; keys that don't exist and keys whose corresponding element is `0` (which is always the encoding of the default value ([1](#user-content-types-overview-overview-of-the-types-direct-types-table-of-direct-types), [2](#user-content-types-overview-overview-of-the-types-multivalue-types), @@ -1209,12 +1216,12 @@ is used; the value can be converted to a string of bytes by the representations listed in the [section on direct types](#user-content-types-overview-overview-of-the-types-direct-types-representations-of-direct-types), with the padding as listed in the [direct types table](#user-content-types-overview-overview-of-the-types-direct-types-table-of-direct-types); for the lookup key type `bytes` ([and `string`](#user-content-types-overview-overview-of-the-types-lookup-types)), -well, this by itself represents a string of bytes! (No padding is applied to -these.) Similarly, the position `p` is regarded as a 32-byte unsigned integer, +well, this by itself represents a string of bytes! (No padding is applied to +these.) Similarly, the position `p` is regarded as a 32-byte unsigned integer, because that is how storage locations are accessed. Note that if an element of a mapping is of direct type, this means it will -always start on a slot boundary, even if it doesn't normally have to. In any +always start on a slot boundary, even if it doesn't normally have to. In any case, regardless of type, the element is stored [exactly the same as it would be anywhere else in storage](#user-content-locations-in-detail-storage-in-detail). @@ -1225,20 +1232,19 @@ anywhere else in storage](#user-content-locations-in-detail-storage-in-detail). Pointers to storage are absolute and are measured in words (slots), not bytes. (Such pointers are most easily regarded as pointing to the full slot, rather than a byte position within it; if you like, though, you can imagine it pointing -to the *latest* position within the word, rather than the earliest, in +to the _latest_ position within the word, rather than the earliest, in accordance with the [right-to-left nature of storage multivalue types](#user-content-locations-in-detail-storage-in-detail-storage-multivalue-types), and the [use of the low -byte](#user-content-locations-in-detail-storage-in-detail-storage-lookup-types) in types `bytes` and `string`.) This might seem to +byte](#user-content-locations-in-detail-storage-in-detail-storage-lookup-types) in types `bytes` and `string`.) This might seem to limit the locations such a pointer can point to; however, pointers to storage will always point to a variable of multivalue or lookup type, and such variables always start on a word boundary, so there is no problem here. -Note that pointers to storage have a default value of `0x0`. As stated earlier, -one must beware -- making use of such a pointer *can* lead to nonsense! Such a -pointer should not actually be used. (And note again that while it is legal to +Note that pointers to storage have a default value of `0x0`. As stated earlier, +one must beware -- making use of such a pointer _can_ lead to nonsense! Such a +pointer should not actually be used. (And note again that while it is legal to leave a storage pointer uninitialized, it is not legal to delete one.) - ---
@@ -1247,7 +1253,6 @@ leave a storage pointer uninitialized, it is not legal to delete one.)
---
-
-[ethdebug/solidity-data-representation](https://github.com/ethdebug/solidity-data-representation)
\ No newline at end of file
+[ethdebug/solidity-data-representation](https://github.com/ethdebug/solidity-data-representation)
diff --git a/content/posts/how-to-generate-ecc-gpg-keys.md b/content/posts/how-to-generate-ecc-gpg-keys.md
index 5c8be2c..9939b54 100644
--- a/content/posts/how-to-generate-ecc-gpg-keys.md
+++ b/content/posts/how-to-generate-ecc-gpg-keys.md
@@ -4,8 +4,8 @@ date: 2021-09-11T16:00:00-07:00
summary: "Generating non-RSA GPG Keys (e.g. Ed25519) is not a straightforward process. This guide outlines the process step by step with best practices."
---
-
# GPG ECC Key Generation
+
> [source documentation](https://www.gniibe.org/memo/software/gpg/keygen-25519.html)
## Overview
@@ -35,16 +35,13 @@ Anyhow, here is the how to.
## Preparation
-- Development version of libgcrypt: git.gnupg.org
-
- You need to clone the master branch and build and install it by
-yourself (from source). Here, we assume that it's installed in
-/usr/local.
-
-- GnuPG 2.1.7 or later
-
- In Debian experimental, we have gnupg2 package.
-
+- Development version of libgcrypt: git.gnupg.org
+ You need to clone the master branch and build and install it by
+ yourself (from source). Here, we assume that it's installed in
+ /usr/local.
+- GnuPG 2.1.7 or later
+
+ In Debian experimental, we have gnupg2 package.
## Example session log
@@ -59,6 +56,7 @@ $ export LD_LIBRARY_PATH=/usr/local/lib
$ gpg-connect-agent KILLAGENT /bye
OK closing connection
```
+
Next, we invoke gpg frontend with --expert and --full-gen-key option.
```bash
@@ -67,6 +65,7 @@ gpg (GnuPG) 2.1.8; Copyright (C) 2015 Free Software Foundation, Inc.
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.
```
+
Then, we input 9 to select ECC primary key and ECC encryption subkey.
```bash
@@ -82,6 +81,7 @@ Please select what kind of key you want:
(11) ECC (set your own capabilities)
Your selection? 9
```
+
Next is the important selection. We input 1 to select "Curve25519".
```bash
@@ -96,13 +96,16 @@ Please select which elliptic curve you want:
(8) secp256k1
Your selection? 1
```
+
You'll see WARNING, but it is what you want.
```bash
gpg: WARNING: Curve25519 is not yet part of the OpenPGP standard.
Use this curve anyway? (y/N) y
```
+
It asks about expiration of key.
+
```bash
Please specify how long the key should be valid.
0 = key does not expire
@@ -114,6 +117,7 @@ Key is valid for? (0)
Key does not expire at all
Is this correct? (y/N) y
```
+
Then, it asks about a user ID.
```bash
@@ -129,6 +133,7 @@ Lastly, it asks confirmation.
Change (N)ame, (C)omment, (E)mail or (O)kay/(Q)uit? o
```
+
Then, it goes like this.
```bash
@@ -141,6 +146,7 @@ some other action (type on the keyboard, move the mouse, utilize the
disks) during the prime generation; this gives the random number
generator a better chance to gain enough entropy.
```
+
It asks the passphrase for keys by pop-up window, and then, finishes.
```bash
@@ -159,7 +165,7 @@ uid [ultimate] Kunisada Chuji