Merge branch 'master' into patch-1

This commit is contained in:
Greg Colvin 2018-09-29 13:29:21 -06:00 committed by GitHub
commit a5ad91dffa
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 364 additions and 143 deletions

View File

@ -107,7 +107,7 @@ This `CALL` utilizes no gas and does not increment the nonce of `NULL_SENDER`
#### Casper Votes
A `vote` transaction is defined as a transaction with the follow parameters:
A `vote` transaction is defined as a transaction with the following parameters:
* `TO`: `CASPER_ADDR`
* `DATA`: Begins with `VOTE_BYTES`

View File

@ -10,7 +10,7 @@ created: 2018-04-20
### Specification
Adds a new opcode at 0xf5, which takes 4 stack arguments: endowment, memory_start, memory_length, salt. Behaves identically to CREATE, except using `sha3(msg.sender ++ salt ++ init_code)[12:]` instead of the usual sender-and-nonce-hash as the address where the contract is initialized at.
Adds a new opcode at 0xf5, which takes 4 stack arguments: endowment, memory_start, memory_length, salt. Behaves identically to CREATE, except using `keccak256(msg.sender ++ salt ++ init_code)[12:]` instead of the usual sender-and-nonce-hash as the address where the contract is initialized at.
### Motivation
@ -18,6 +18,6 @@ Allows interactions to (actually or counterfactually in channels) be made with a
#### Option 2
Use `sha3(0xff ++ msg.sender ++ salt ++ init_code)[12:]`
Use `keccak256(0xff ++ msg.sender ++ salt ++ init_code)[12:]`
Rationale: ensures that addresses created with this scheme cannot collide with addresses created using the traditional `sha3(rlp([sender, nonce]))` formula, as 0xff can only be a starting byte for RLP for data many petabytes long.
Rationale: ensures that addresses created with this scheme cannot collide with addresses created using the traditional `keccak256(rlp([sender, nonce]))` formula, as 0xff can only be a starting byte for RLP for data many petabytes long.

View File

@ -13,8 +13,12 @@ requires: 196, 197
Recent changes to the underlying library used by the official Go reference
implementation led to significant performance gains for the `ECADD`, `ECMUL`,
and pairing check precompiled contracts on the `alt_bn128` elliptic curve, which
should be reflected in reduced gas costs.
and pairing check precompiled contracts on the `alt_bn128` elliptic curve.
What is more, the performance boost for those operations can be also observed
for Parity client.
Faster operations on Ethereum clients should be reflected in reduced gas costs.
## Motivation
@ -29,20 +33,30 @@ note](https://github.com/ethereum/go-ethereum/pull/16301#issuecomment-372687543)
the computational cost of `ECADD`, `ECMUL`, and pairing checks (excepting the
constant) has dropped roughly an order of magnitude across the board.
Also, [optimisations in the bn library](https://github.com/paritytech/bn/pull/9)
used by the [Parity client](https://github.com/paritytech/parity-ethereum) led to a
significant performance boost we
[benchmarked](https://gist.github.com/pdyraga/4649b74436940a01e8221d85e80bfeef)
and compared against the [previous
results](https://github.com/ethereum/benchmarking/blob/master/constantinople/analysis2.md).
## Specification
Following is a table with the current gas cost and new gas cost:
| Contract | Address | Current Gas Cost | Updated Gas Cost |
| ------------- | --------- | ----------------------------- | ------------------- |
| `ECADD` | `0x06` | 500<sup>[1]</sup> | 50 |
| `ECMUL` | `0x07` | 40 000<sup>[1]</sup> | 2 000 |
| Pairing check | `0x08` | 80 000k + 100 000<sup>[2]</sup>| 5 500k + 80 000 |
| `ECADD` | `0x06` | 500<sup>[1]</sup> | 150 |
| `ECMUL` | `0x07` | 40 000<sup>[1]</sup> | 6 000 |
| Pairing check | `0x08` | 80 000 * k + 100 000<sup>[2]</sup>| 28 300 * k + 35 450 |
The gas costs for `ECADD` and `ECMUL` are updates to the costs listed in
EIP-196, while the gas costs for the pairing check are updates to the cost
listed in EIP-197.
listed in EIP-197. Updated gas costs have been adjusted to the less performant
client which is Parity, according to benchmarks<sup>[3]</sup>.
[1]- Per [EIP-196](https://github.com/ethereum/EIPs/blob/984cf5de90bbf5fbe7e49be227b0c2f9567e661e/EIPS/eip-196.md#gas-costs).
[2]- Per [EIP-197](https://github.com/ethereum/EIPs/blob/df132cd37efb3986f9cd3ef4922b15a767d2c54a/EIPS/eip-197.md#specification).
[3]- [Parity benchmarks.](https://gist.github.com/pdyraga/4649b74436940a01e8221d85e80bfeef)

View File

@ -27,10 +27,12 @@ By default a "read-only" provider is supplied to allow access to the blockchain
A full provider can be requested to allow account-level methods:
```js
ethereum.enable(): Promise<[String]>;
ethereum.enable(): Promise<Boolean>;
```
Promise resolves with an array of the accounts' public keys, or rejects with `Error`.
This shows a dialog to the user asking if they would like to authenticate any account(s) to the dapp.
Promise resolves with `True`, or rejects with `Error`.
### Send
@ -49,12 +51,14 @@ See the [available methods](https://github.com/ethereum/wiki/wiki/JSON-RPC#json-
#### Subscribe
```js
ethereum.subscribe(subscriptionType: String, params?: Array<any>): Promise<String>;
ethereum.subscribe(subscriptionType: String, subscriptionMethod: String, params?: Array<any>): Promise<String>;
```
Promise resolves with `subscriptionId: String` or rejects with `Error`.
`subscriptionType` is expected to be `eth_subscribe` or `shh_subscribe`.
See the [types of subscriptions](https://github.com/ethereum/go-ethereum/wiki/RPC-PUB-SUB#supported-subscriptions).
See the [eth subscription methods](https://github.com/ethereum/go-ethereum/wiki/RPC-PUB-SUB#supported-subscriptions) and [shh subscription methods](https://github.com/ethereum/go-ethereum/wiki/Whisper-v6-RPC-API#shh_subscribe).
Promise resolves with `subscriptionId: String` or rejects with `Error`.
Results emit on `subscriptionId` using [EventEmitter](https://nodejs.org/api/events.html). Attach listeners with:
@ -67,9 +71,11 @@ The event emits with `result`, the subscription `result` or an `Error` object.
#### Unsubscribe
```js
ethereum.unsubscribe(subscriptionId: String): Promise<Boolean>;
ethereum.unsubscribe(subscriptionType: String, subscriptionId: String): Promise<Boolean>;
```
`subscriptionType` is expected to be `eth_unsubscribe` or `shh_unsubscribe`.
Promise resolves with `success: Boolean` or rejects with `Error`.
All [EventEmitter](https://nodejs.org/api/events.html) listeners on `subscriptionId` will also be removed.
@ -155,8 +161,23 @@ ethereum
// Example 2: Enable full provider
ethereum
.enable()
.then(accounts => {
console.log(`Enabled accounts:\n${accounts.join('\n')}`);
.then(success => {
if (success) {
console.log(`Ethereum provider enabled enabled!`);
// Example 3: Log available accounts
ethereum
.send('eth_accounts')
.then(accounts => {
console.log(`Accounts:\n${accounts.join('\n')}`);
})
.catch(error => {
console.error(
`Error fetching accounts: ${error.message}.
Code: ${error.code}. Data: ${error.data}`
);
});
}
})
.catch(error => {
console.error(
@ -165,24 +186,10 @@ ethereum
);
});
// Example 3: Log available accounts
ethereum
.send('eth_accounts')
.then(accounts => {
console.log(`Accounts:\n${accounts.join('\n')}`);
})
.catch(error => {
console.error(
`Error fetching accounts: ${error.message}.
Code: ${error.code}. Data: ${error.data}`
);
});
}
// Example 4: Log new blocks
let subId;
ethereum
.subscribe('newHeads')
.subscribe('eth_subscribe', 'newHeads')
.then(subscriptionId => {
subId = subscriptionId;
ethereum.on(subscriptionId, block => {
@ -205,7 +212,7 @@ ethereum
});
// to unsubscribe
ethereum
.unsubscribe(subId)
.unsubscribe('eth_unsubscribe', subId)
.then(result => {
console.log(`Unsubscribed newHeads subscription ${subscriptionId}`);
})
@ -236,13 +243,13 @@ ethereum.on('close', (code, reason) => {
### Enable
The provider supplied to a new dapp **MUST** be a "read-only" provider: authenticating no accounts by default, returning a blank array for `eth_accounts`, and rejecting any methods that require an account.
The provider supplied to a new dapp **MUST** be a "read-only" provider: authenticating no accounts by default, returning a blank array for `eth_accounts`, and rejecting any methods that require an account with Error code 4100.
If the dapp has been previously authenticated and remembered by the user, then the provider supplied on load **MAY** automatically be enabled with the previously authenticated accounts.
If no accounts are authenticated, the `enable` method **MUST** ask the user which account(s) they would like to authenticate to the dapp. If the request has been previously granted and remembered, the `enable` method **MAY** immediately return with the prior remembered accounts and permissions.
If no accounts are authenticated, the `enable` method **MUST** ask the user which account(s) they would like to authenticate to the dapp. If the request has been previously granted and remembered, the `enable` method **MAY** immediately return.
The `enable` method **MUST** return a Promise, resolving with an array of the accounts' public keys, or rejecting with an `Error`. If the accounts enabled by provider change, the `accountsChanged` event **MUST** also emit.
The `enable` method **MUST** return a Promise that resolves with true or rejects with an `Error`. If the accounts enabled by provider change, the `accountsChanged` event **MUST** also emit.
### Send
@ -260,17 +267,17 @@ If the JSON-RPC request requires an account that is not yet authenticated, the P
### Subscriptions
The `subscribe` method **MUST** send a properly formatted [JSON-RPC request](https://www.jsonrpc.org/specification#request_object) with method `eth_subscribe` and params `[subscriptionType: String, {...params: Array<any>}]` and **MUST** return a Promise that resolves with `subscriptionId: String` or rejected with an Error object.
The `subscribe` method **MUST** send a properly formatted [JSON-RPC request](https://www.jsonrpc.org/specification#request_object) with method `subscriptionType` (`eth_subscribe` or `shh_subscribe`) and params `[subscriptionMethod: String, ...params: Array<any>]`. It **MUST** return a Promise that resolves with `id: String` or rejects with an Error object.
The `unsubscribe` method **MUST** send a properly formatted [JSON-RPC request](https://www.jsonrpc.org/specification#request_object) with method `eth_unsubscribe` and params `[subscriptionId: String]` and **MUST** return a Promise that resolves with `result: Boolean` or rejected with an Error object.
The `unsubscribe` method **MUST** send a properly formatted [JSON-RPC request](https://www.jsonrpc.org/specification#request_object) with method `subscriptionType` (`eth_unsubscribe` or `shh_unsubscribe`) and params `[subscriptionId: String]`. It **MUST** return a Promise that resolves with `result: Boolean` or rejects with an Error object.
If the `unsubscribe` method returns successfully with a `True` result, the implementing provider **MUST** remove all listeners on the `subscriptionId` using `ethereum.removeAllListeners(subscriptionId);`.
If an error occurs during processing of the subscription, such as an HTTP error or internal parsing error then the Promise **MUST** return with an Error object.
The implementing Ethereum Provider **MUST** emit every subscription response `result` with the eventName `subscriptionId`.
The implementing Ethereum Provider **MUST** emit every subscription response `result` to the eventName of the `subscriptionId`.
If an error occurs or the network changes during the listening of the subscription, the Ethereum Provider **MUST** emit an Error object to the eventName `subscriptionId`.
If an error occurs or the network changes during the listening of the subscription, the Ethereum Provider **MUST** emit an Error object to the eventName of the `subscriptionId`.
If the implementing provider does not support subscriptions, then it **MUST** leave the `subscribe` and `unsubscribe` methods undefined.
@ -288,9 +295,9 @@ If the accounts connected to the Ethereum Provider change, the Ethereum Provider
The name of the constructor of the Ethereum Provider **MUST** be `EthereumProvider`.
### web3.js Provider
### web3.js Backwards Compatibility
The implementing Ethereum Provider **MUST** be compatible as a `web3.js` provider. This is accomplished by providing two methods in the `EthereumProvider`: `sendAsync(payload: Object, callback: (error: any, result: any) => void): void` and `isConnected(): Boolean`.
If the implementing Ethereum Provider would like to be compatible with `web3.js` prior to `1.0.0-beta37`, it **MUST** provide two methods: `sendAsync(payload: Object, callback: (error: any, result: any) => void): void` and `isConnected(): Boolean`.
### Error object and codes
@ -298,11 +305,11 @@ If an Error object is returned, it **MUST** contain a human readable string mess
Appropriate error codes **SHOULD** follow the table of [`CloseEvent` status codes](https://developer.mozilla.org/en-US/docs/Web/API/CloseEvent#Status_codes), along with the following table:
| Status code | Name | Description |
| ----------- | ------------------------- | -------------------------------------------------------------------------------------------------------------- |
| 4001 | User Denied Full Provider | User denied the enabling of the full Ethereum Provider by choosing not to authorize any accounts for the dapp. |
| | | |
| | | |
| Status code | Name | Description |
| ----------- | -------------------------- | ------------------------------------------------------------------------------------------------------- |
| 4001 | User Denied Full Provider | User denied enabling the full Ethereum Provider by choosing not to authorize any accounts for the dapp. |
| 4010 | User Denied Create Account | User denied creating a new account. |
| 4100 | Unauthorized | The requested account has not been authorized by the user. |
## Sample Class Implementation
@ -362,16 +369,16 @@ class EthereumProvider extends EventEmitter {
return promise;
}
subscribe(subscriptionType, params) {
return this.send('eth_subscribe', [subscriptionType, ...params]).then(
subscribe(subscriptionType, subscriptionMethod, params) {
return this.send(subscriptionType, [subscriptionMethod, ...params]).then(
subscriptionId => {
this._activeSubscriptions.push(subscriptionId);
}
);
}
unsubscribe(subscriptionId) {
return this.send('eth_unsubscribe', [subscriptionId]).then(success => {
unsubscribe(subscriptionType, subscriptionId) {
return this.send(subscriptionType, [subscriptionId]).then(success => {
if (success) {
// Remove subscription
this._activeSubscription = this._activeSubscription.filter(
@ -470,7 +477,7 @@ class EthereumProvider extends EventEmitter {
this.emit('accountsChanged', accounts);
}
/* web3.js provider compatibility */
/* web3.js Provider Backwards Compatibility */
sendAsync(payload, callback) {
return this.send(payload.method, payload.params)

View File

@ -21,12 +21,12 @@ created: 2016-09-24
### Specification
If `block.number >= FORK_BLKNUM`, then:
- Increase the gas cost of EXTCODESIZE to 700.
- Increase the base gas cost of EXTCODECOPY to 700.
- Increase the gas cost of BALANCE to 400.
- Increase the gas cost of SLOAD to 200.
- Increase the gas cost of CALL, DELEGATECALL, CALLCODE to 700.
- Increase the gas cost of SELFDESTRUCT to 5000.
- Increase the gas cost of EXTCODESIZE to 700 (from 20).
- Increase the base gas cost of EXTCODECOPY to 700 (from 20).
- Increase the gas cost of BALANCE to 400 (from 20).
- Increase the gas cost of SLOAD to 200 (from 50).
- Increase the gas cost of CALL, DELEGATECALL, CALLCODE to 700 (from 40).
- Increase the gas cost of SELFDESTRUCT to 5000 (from 0).
- If SELFDESTRUCT hits a newly created account, it triggers an additional gas cost of 25000 (similar to CALLs).
- Increase the recommended gas limit target to 5.5 million.
- Define "all but one 64th" of `N` as `N - floor(N / 64)`.

View File

@ -68,7 +68,7 @@ This input data:
fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe
fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffd
Would parse a base length of 0, a exponent length of 32, and an exponent length of `2**256 - 1`, where the base is empty, the exponent is `2**256 - 2` and the modulus is `(2**256 - 3) * 256**(2**256 - 33)` (yes, that's a really big number). It would then immediately fail, as it's not possible to provide enough gas to make that computation.
Would parse a base length of 0, an exponent length of 32, and a modulus length of `2**256 - 1`, where the base is empty, the exponent is `2**256 - 2` and the modulus is `(2**256 - 3) * 256**(2**256 - 33)` (yes, that's a really big number). It would then immediately fail, as it's not possible to provide enough gas to make that computation.
This input data:
@ -91,7 +91,7 @@ This input data:
ffff
80
Would also parse as a base of 3, an exponent of 65535 and a modulus of `2**255`, as it attempts to grab 32 bytes for the modulus starting from 0x80, but then there is no further data so it right pads it with 31 zeroes.
Would also parse as a base of 3, an exponent of 65535 and a modulus of `2**255`, as it attempts to grab 32 bytes for the modulus starting from 0x80 - but there is no further data, so it right-pads it with 31 zero bytes.
# Rationale

View File

@ -67,7 +67,7 @@ A good hashing algorithm should satisfy security properties such as determinism,
### Transactions and bytestrings
An illustrative example of the above breakage can be found in Ethereum. Ethereum has two kinds of messages, transactions `𝕋` and bytestrings `𝔹⁸ⁿ`. These are signed using `eth_sendTransaction` and `eth_sign` respectively. Originally the encoding function `encode : 𝕋 𝔹⁸ⁿ → 𝔹⁸ⁿ` was as defined as follows:
An illustrative example of the above breakage can be found in Ethereum. Ethereum has two kinds of messages, transactions `𝕋` and bytestrings `𝔹⁸ⁿ`. These are signed using `eth_sendTransaction` and `eth_sign` respectively. Originally the encoding function `encode : 𝕋 𝔹⁸ⁿ → 𝔹⁸ⁿ` was defined as follows:
* `encode(t : 𝕋) = RLP_encode(t)`
* `encode(b : 𝔹⁸ⁿ) = b`
@ -93,7 +93,7 @@ Both determinism and injectiveness would be trivially true if `len(b)` was left
The `eth_sign` call assumes messages to be bytestrings. In practice we are not hashing bytestrings but the collection of all semantically different messages of all different DApps `𝕄`. Unfortunately, this set is impossible to formalize. Instead we approximate it with the set of typed named structures `𝕊`. This standard formalizes the set `𝕊` and provides a deterministic injective encoding function for it.
Just encoding structs is not enough. It is likely that two different DApps use identical structs. When this happens, a signed message intended for one DApp would also be valid for the other. The signatures are compatible. This can be intended behaviour, in which case everything is fine as long as the DApps took replay attacks into consideration. If it is not intended, there is a security problem.
Just encoding structs is not enough. It is likely that two different DApps use identical structs. When this happens, a signed message intended for one DApp would also be valid for the other. The signatures are compatible. This can be intended behaviour, in which case everything is fine as long as the DApps took replay attacks into consideration. If it is not intended, there is a security problem.
The way to solve this is by introducing a domain separator, a 256-bit number. This is a value unique to each domain that is 'mixed in' the signature. It makes signatures from different domains incompatible. The domain separator is designed to include bits of DApp unique information such as the name of the DApp, the intended validator contract address, the expected DApp domain name, etc. The user and user-agent can use this information to mitigate phishing attacks, where a malicious DApp tries to trick the user into signing a message for another DApp.
@ -157,7 +157,7 @@ If the struct type references other struct types (and these in turn reference ev
### Definition of `encodeData`
The encoding of a struct instance is `enc(value₁) ‖ enc(value₂) ‖ … ‖ enc(valueₙ)`, i.e. the concatenation of the encoded of the member values in the order that they apear in the type. Each encoded member value is exactly 32-byte long.
The encoding of a struct instance is `enc(value₁) ‖ enc(value₂) ‖ … ‖ enc(valueₙ)`, i.e. the concatenation of the encoded member values in the order that they apear in the type. Each encoded member value is exactly 32-byte long.
The atomic values are encoded as follows: Boolean `false` and `true` are encoded as `uint256` values `0` and `1` respectively. Addresses are encoded as `uint160`. Integer values are sign-extended to 256-bit and encoded in big endian order. `bytes1` to `bytes31` are arrays with a beginning (index `0`) and an end (index `length - 1`), they are zero-padded at the end to `bytes32` and encoded in beginning to end order. This corresponds to their encoding in ABI v1 and v2.
@ -262,7 +262,7 @@ Result:
}
```
An example how to use solidity ecrecover to verify the signature calculated with `eth_signTypedData` can be found in the EIP712 [Example.js][example-js]. The contract is deployed on the testnet Ropsten and Rinkeby.
An example how to use Solidity ecrecover to verify the signature calculated with `eth_signTypedData` can be found in the EIP712 [Example.js][example-js]. The contract is deployed on the testnet Ropsten and Rinkeby.
[example-js]: https://github.com/ethereum/EIPs/blob/master/assets/eip-712/Example.js
@ -326,9 +326,9 @@ The domain separator prevents collision of otherwise identical structures. It is
The domain separator also allows for multiple distinct signatures use-cases on the same struct instance within a given DApp. In the previous example, perhaps signatures from both `from` and `to` are required. By providing two distinct domain separators these signatures can be distinguished from each other.
**Alternative 1**: Use the target contract address as domain separator. This solves the first problem, contracts coming up with identical types, but does not address second use-case. The standard does suggest implementors to use the target contract address where this is appropriate.
**Alternative 1**: Use the target contract address as domain separator. This solves the first problem, contracts coming up with identical types, but does not address the second use-case. The standard does suggest implementors to use the target contract address where this is appropriate.
The function `hashStruct` starts with a `typeHash` to separate types. By giving different types a different prefix the `encodeData` function only has to be injective for within a given type. It is okay for `encodeData(a)` to equal `encodeData(b)` as long as `typeOf(a)` is not `typeOf(b)`.
The function `hashStruct` starts with a `typeHash` to separate types. By giving different types a different prefix the `encodeData` function only has to be injective within a given type. It is okay for `encodeData(a)` to equal `encodeData(b)` as long as `typeOf(a)` is not `typeOf(b)`.
### Rationale for `typeHash`
@ -339,11 +339,11 @@ bytes32 constant MAIL_TYPEHASH = keccak256(
"Mail(address from,address to,string contents)");
```
For the type hash several alternatives where considered and rejected for the reasons:
For the type hash several alternatives were considered and rejected for the reasons:
**Alternative 2**: Use ABIv2 function signatures. `bytes4` is not enough to be collision resistant. Unlike function signatures, there is negligible runtime cost incurred by using longer hashes.
**Alternative 3**: ABIv2 function signatures modified to be 256-bit. While this captures type info, it does not capture any of the semantics other than the function. This is already causing a practical collision between ERC20's and ERC721's `transfer(address,uint256)`, where in the former the `uint256` revers to an amount and the latter to a unique id. In general ABIv2 favors compatibility where a hashing standard should prefer incompatibility.
**Alternative 3**: ABIv2 function signatures modified to be 256-bit. While this captures type info, it does not capture any of the semantics other than the function. This is already causing a practical collision between ERC20's and ERC721's `transfer(address,uint256)`, where in the former the `uint256` refers to an amount and the latter to a unique id. In general ABIv2 favors compatibility where a hashing standard should prefer incompatibility.
**Alternative 4**: 256-bit ABIv2 signatures extended with parameter names and struct names. The `Mail` example from a above would be encoded as `Mail(Person(string name,address wallet) from,Person(string name,address wallet) to,string contents)`. This is longer than the proposed solution. And indeed, the length of the string can grow exponentially in the length of the input (consider `struct A{B a;B b;}; struct B {C a;C b;}; …`). It also does not allow a recursive struct type (consider `struct List {uint256 value; List next;}`).
@ -375,24 +375,24 @@ function hashStruct(Mail memory mail) pure returns (bytes32 hash) {
assembly {
// Back up select memory
let temp1 := mload(sub(order, 32))
let temp2 := mload(add(order, 128))
let temp1 := mload(sub(mail, 32))
let temp2 := mload(add(mail, 128))
// Write typeHash and sub-hashes
mstore(sub(mail, 32), typeHash)
mstore(add(order, 64), contentsHash)
mstore(add(mail, 64), contentsHash)
// Compute hash
hash := keccak256(sub(order, 32), 128)
hash := keccak256(sub(mail, 32), 128)
// Restore memory
mstore(sub(order, 32), temp1)
mstore(add(order, 64), temp2)
mstore(sub(mail, 32), temp1)
mstore(add(mail, 64), temp2)
}
}
```
The in-place implementation makes strong but reasonable assumptions on the memory layout of structs in memory. Specifically it assume structs are not allocated below address 32, that members are stored in order, that all values are padded to 32-byte boundaries, and that dynamic and reference types are stored as a 32-byte pointers.
The in-place implementation makes strong but reasonable assumptions on the memory layout of structs in memory. Specifically it assumes structs are not allocated below address 32, that members are stored in order, that all values are padded to 32-byte boundaries, and that dynamic and reference types are stored as a 32-byte pointers.
**Alternative 6**: Tight packing. This is the default behaviour in Soldity when calling `keccak256` with multiple arguments. It minimizes the number of bytes to be hashed but requires complicated packing instructions in EVM to do so. It does not allow in-place computation.
@ -400,7 +400,7 @@ The in-place implementation makes strong but reasonable assumptions on the memor
**Alternative 8**: Leave `typeHash` out of `hashStruct` and instead combine it with the domain separator. This is more efficient, but then the semantics of the Solidity `keccak256` hash function are not injective.
**Alternative 9**: Support cyclical data structures. The current standard is optimized for tree-like data structures and undefined for cyclical data structures. To support cyclical data a stack containing the path to the current node needs to be maintained and a stack offset substituted when a cycle is detected. This is prohibitively more complex to specify and implement. It also breaks composability where the hashes of the member values are used to construct the hash of the struct (the hash of the member values would dependent on the path). It is possible to extend the standard in a compatible way to define hashes of cyclical data.
**Alternative 9**: Support cyclical data structures. The current standard is optimized for tree-like data structures and undefined for cyclical data structures. To support cyclical data a stack containing the path to the current node needs to be maintained and a stack offset substituted when a cycle is detected. This is prohibitively more complex to specify and implement. It also breaks composability where the hashes of the member values are used to construct the hash of the struct (the hash of the member values would depend on the path). It is possible to extend the standard in a compatible way to define hashes of cyclical data.
Similarly, a straightforward implementation is sub-optimal for directed acyclic graphs. A simple recursion through the members can visit the same node twice. Memoization can optimize this.
@ -408,7 +408,7 @@ Similarly, a straightforward implementation is sub-optimal for directed acyclic
Since different domains have different needs, an extensible scheme is used where the DApp specifies a `EIP712Domain` struct type and an instance `eip712Domain` which it passes to the user-agent. The user-agent can then apply different verification measures depending on the fields that are there.
A field `string eip719dsl` can added and be rejected if the value does not match the hash of the [EIP-719][eip719] DSL interface string.
A field `string eip719dsl` can be added and be rejected if the value does not match the hash of the [EIP-719][eip719] DSL interface string.
[eip719]: https://github.com/ethereum/EIPs/issues/719
@ -424,7 +424,7 @@ The Solidity expression `keccak256(someInstance)` for an instance `someInstance`
<!-- Test cases for an implementation are mandatory for EIPs that are affecting consensus changes. Other EIPs can choose to include links to test cases if applicable. -->
An example contract can be found in [Example.sol][ex-sol] and an example implementation of signing in Javascrtip in [Example.js][ex-js]
An example contract can be found in [Example.sol][ex-sol] and an example implementation of signing in JavaScript in [Example.js][ex-js]
[ex-sol]: https://github.com/ethereum/EIPs/blob/master/assets/eip-712/Example.sol
[ex-js]: https://github.com/ethereum/EIPs/blob/master/assets/eip-712/Example.js

View File

@ -10,14 +10,14 @@ created: 2017-10-02
---
## Simple Summary
Proxy contract for key management and execution, to establish a Blockchain identity.
A proxy contract for key management and execution, to establish a Blockchain identity.
## Abstract
The following describes standard functions for a unique identity for humans, groups, objects and machines.
This identity can hold keys to sign actions (transactions, documents, logins, access, etc), and claims, which are attested from third parties (issuers) and self attested ([#ERC735](https://github.com/ethereum/EIPs/issues/735)), as well as a proxy function to act directly on the blockchain.
This identity can hold keys to sign actions (transactions, documents, logins, access, etc), and claims, which are attested from third parties (issuers) and self-attested ([#ERC735](https://github.com/ethereum/EIPs/issues/735)), as well as a proxy function, to act directly on the blockchain.
## Motivation
This standardised identity interface will allow Dapps, smart contracts and thirdparties to check the validity of a person, organisation, object or machine through 2 steps as described in the function XXX. Trust is here transfered to the issuers of claims.
This standardized identity interface will allow Dapps, smart contracts and third parties to check the validity of a person, organization, object or machine through 2 steps as described in the function XXX. Trust is here transferred to the issuers of claims.
The most important functions to verify an identity are: `XXX`
@ -26,7 +26,7 @@ The most important functions to manage an identity are: `XXX`
## Definitions
- `keys`: Keys are public keys from either external accounts, or contract addresses.
- `keys`: Keys are public keys from either external accounts, or contracts' addresses.
- `claim issuer`: is another smart contract or external account, which issues claims about this identity. The claim issuer can be an identity contract itself.
- `claim`: For details about claims see [#ERC735](https://github.com/ethereum/EIPs/issues/735)
@ -64,7 +64,7 @@ function getKey(bytes32 _key) constant returns(uint256[] purposes, uint256 keyTy
#### keyHasPurpose
Returns the `TRUE` if a key has is present and has the given purpose. If key is not present it returns `FALSE`.
Returns the `TRUE` if a key has is present and has the given purpose. If the key is not present it returns `FALSE`.
``` js
function keyHasPurpose(bytes32 _key, uint256 purpose) constant returns(bool exists);
@ -82,11 +82,11 @@ function getKeysByPurpose(uint256 _purpose) constant returns(bytes32[] keys);
#### addKey
Adds a `_key` to the identity. The `_purpose` specifies the purpose of key. Initially we propose four purposes:
Adds a `_key` to the identity. The `_purpose` specifies the purpose of the key. Initially, we propose four purposes:
- `1`: MANAGEMENT keys, which can manage the identity
- `2`: ACTION keys, which perform actions in this identities name (signing, logins, transactions, etc.)
- `3`: CLAIM signer keys, used to sign claims on other identities which need to be revokable.
- `3`: CLAIM signer keys, used to sign claims on other identities which need to be revocable.
- `4`: ENCRYPTION keys, used to encrypt data e.g. hold in claims.
MUST only be done by keys of purpose `1`, or the identity itself. If its the identity itself, the approval process will determine its approval.
@ -121,9 +121,9 @@ function removeKey(bytes32 _key, uint256 _purpose) returns (bool success)
Executes an action on other contracts, or itself, or a transfer of ether.
SHOULD require `approve` to be called with one or more keys of purpose `1` or `2` to approve this execution.
Execute COULD be used as the only accessors for `addKey`, `removeKey` and `replaceKey` and `removeClaim`.
Execute COULD be used as the only accessor for `addKey`, `removeKey` and `replaceKey` and `removeClaim`.
**Returns `executionId`:** SHOULD be send to the `approve` function, to approve or reject this execution.
**Returns `executionId`:** SHOULD be sent to the `approve` function, to approve or reject this execution.
**Triggers Event:** [ExecutionRequested](#executionrequested)
**Triggers on direct execution Event:** [Executed](#executed)
@ -136,8 +136,8 @@ function execute(address _to, uint256 _value, bytes _data) returns (uint256 exec
#### approve
Approves an execution or claim addition.
This SHOULD require `n` of `m` approvals of keys purpose `1`, if the `_to` of the execution is the identity contract itself, to successfull approve an execution.
And COULD require `n` of `m` approvals of keys purpose `2`, if the `_to` of the execution is another contract, to successfull approve an execution.
This SHOULD require `n` of `m` approvals of keys purpose `1`, if the `_to` of the execution is the identity contract itself, to successfully approve an execution.
And COULD require `n` of `m` approvals of keys purpose `2`, if the `_to` of the execution is another contract, to successfully approve an execution.
**Triggers Event:** [Approved](#approved)
**Triggers on successfull execution Event:** [Executed](#executed)
@ -159,7 +159,7 @@ Requires: [ERC 735](https://github.com/ethereum/EIPs/issues/735)
#### addClaim
This SHOULD create a pending claim, which SHOULD to be approved or rejected by `n` of `m` `approve` calls from keys of purpose `1`.
This SHOULD create a pending claim, which SHOULD be approved or rejected by `n` of `m` `approve` calls from keys of purpose `1`.
Only Events:
**Triggers if the claim is new Event and approval process exists:** [ClaimRequested](#claimrequested)
@ -241,9 +241,9 @@ MUST be triggered when `approve` was called and the claim was successfully added
## Rationale
This specification was chosen to allow most flexibility and experimention around identity. By having each identity in a separate contract it allows for cross identity compatibility, but at the same time extra and altered functionality for new use cases.
This specification was chosen to allow most flexibility and experimentation around identity. By having each identity in a separate contract it allows for cross identity compatibility, but at the same time extra and altered functionality for new use cases.
The main critic of this standard is the verification where each identity that issues a claim, also should have a separate CLAIM signing key attached. While [#ERC780](https://github.com/ethereum/EIPs/issues/780) uses a standardised registry to assign claims to addresses.
The main critic of this standard is the verification where each identity that issues a claim, also should have a separate CLAIM signing key attached. While [#ERC780](https://github.com/ethereum/EIPs/issues/780) uses a standardized registry to assign claims to addresses.
Both systems could work in conjunction and should be explored.
While also off-chain claims using DID verifiable claims and merkle tries can be added as claims and should be explored.

View File

@ -1,7 +1,7 @@
---
eip: 918
title: Mineable Token Standard
author: Jay Logelin <jlogelin@fas.harvard.edu>, Infernal_toast <admin@0xbitcoin.org>, Michael Seiler <mgs33@cornell.edu>
author: Jay Logelin <jlogelin@fas.harvard.edu>, Infernal_toast <admin@0xbitcoin.org>, Michael Seiler <mgs33@cornell.edu>, Brandon Grill <bg2655@columbia.edu>
type: Standards Track
category: ERC
status: Draft
@ -18,27 +18,37 @@ This specification describes a method for initially locking tokens within a toke
### Motivation
Token distribution via the ICO model and it's derivatives is susceptable to illicit behavior by human actors. Furthermore, new token projects are centralized because a single entity must handle and control all of the initial coins and all of the the raised ICO money. By distributing tokens via an 'Initial Mining Offering' (or IMO), the ownership of the token contract no longer belongs with the deployer at all and the deployer is 'just another user.' As a result, investor risk exposure utilizing a mined token distribution model is significantly diminished. This standard is intended to be standalone, allowing maximum interoperability with ERC20, ERC721, and others.
Token distribution via the ICO model and its derivatives is susceptible to illicit behavior by human actors. Furthermore, new token projects are centralized because a single entity must handle and control all of the initial coins and all of the raised ICO money. By distributing tokens via an 'Initial Mining Offering' (or IMO), the ownership of the token contract no longer belongs with the deployer at all and the deployer is 'just another user.' As a result, investor risk exposure utilizing a mined token distribution model is significantly diminished. This standard is intended to be standalone, allowing maximum interoperability with ERC20, ERC721, and others.
### Specification
#### Interface
The general behavioral specification includes a primary function that defines the token minting operation, an optional merged minting operation for issuing multiple tokens, getters for challenge number, mining difficulty, mining target and current reward, and finally a Mint event, to be emitted upon successful solution validation and token issuance. At a minimum, contracts must adhere to this interface (save the optional merge operation). It is recommended that contracts interface with the more behaviorally defined Abstract Contract described below, in order to leverage a more defined construct, allowing for easier external implementations via overridden phased functions. (see 'Abstract Contract' below)
``` js
contract EIP918Interface {
function mint(uint256 nonce) public returns (bool success);
function merge(uint256 nonce, address[] mineTokens) public returns (bool) {}
function getAdjustmentInterval() public view returns (uint);
function getChallengeNumber() public view returns (bytes32);
function getMiningDifficulty() public view returns (uint);
function getMiningTarget() public view returns (uint);
function getMiningReward() public view returns (uint);
function hash(uint256 nonce) public returns (bytes32 digest);
function _reward() internal returns (uint);
function _epoch() internal returns (uint);
function _adjustDifficulty() internal returns (uint);
event Mint(address indexed from, uint reward_amount, uint epochCount, bytes32 newChallengeNumber);
``` solidity
contract ERC918 {
function mint(uint256 nonce) public returns (bool success);
function getAdjustmentInterval() public view returns (uint);
function getChallengeNumber() public view returns (bytes32);
function getMiningDifficulty() public view returns (uint);
function getMiningTarget() public view returns (uint);
function getMiningReward() public view returns (uint);
function hash(uint256 _nonce, address _minter) public returns (bytes32 digest);
function _reward(address _minter) internal returns (uint);
function _epoch() internal returns (uint);
function _adjustDifficulty() internal returns (uint);
event Mint(address indexed from, uint rewardAmount, uint epochCount, bytes32 newChallengeNumber);
}
```
@ -51,35 +61,35 @@ The Abstract Contract adheres to the EIP918 Interface and extends behavioral def
#### adjustmentInterval
The amount of time between difficulty adjustments in seconds.
``` js
``` solidity
bytes32 public adjustmentInterval;
```
#### challengeNumber
The current challenge number. It is expected tha a new challenge number is generated after a new reward is minted.
``` js
``` solidity
bytes32 public challengeNumber;
```
#### difficulty
The current mining difficulty which should be adjusted via the \_adjustDifficulty minting phase
``` js
``` solidity
uint public difficulty;
```
#### tokensMinted
Cumulative counter of the total minted tokens, usually modified during the \_reward phase
``` js
``` solidity
uint public tokensMinted;
```
#### epochCount
Number of 'blocks' mined
``` js
``` solidity
uint public epochCount;
```
@ -87,7 +97,7 @@ uint public epochCount;
#### mint
Returns a flag indicating a successful hash digest verification, and reward allocation to msg.sender. In order to prevent MiTM attacks, it is recommended that the digest include a recent ethereum block hash and msg.sender's address. Once verified, the mint function calculates and delivers a mining reward to the sender and performs internal accounting operations on the contract's supply.
Returns a flag indicating a successful hash digest verification, and reward allocation to msg.sender. In order to prevent MiTM attacks, it is recommended that the digest include a recent Ethereum block hash and msg.sender's address. Once verified, the mint function calculates and delivers a mining reward to the sender and performs internal accounting operations on the contract's supply.
The mint operation exists as a public function that invokes 4 separate phases, represented as functions hash, \_reward, \_newEpoch, and \_adjustDifficulty. In order to create the most flexible implementation while adhering to a necessary contract protocol, it is recommended that token implementors override the internal methods, allowing the base contract to handle their execution via mint.
@ -95,7 +105,7 @@ This externally facing function is called by miners to validate challenge digest
populate statistics, mutate epoch variables and adjust the solution difficulty as required. Once complete,
a Mint event is emitted before returning a boolean success flag.
``` js
``` solidity
contract AbstractERC918 is EIP918Interface {
// the amount of time between difficulty adjustments
@ -152,25 +162,15 @@ contract AbstractERC918 is EIP918Interface {
Upon successful verification and reward the mint method dispatches a Mint Event indicating the reward address, the reward amount, the epoch count and newest challenge number.
``` js
``` solidity
event Mint(address indexed from, uint reward_amount, uint epochCount, bytes32 newChallengeNumber);
```
#### merge
*Optional*
Operationally similar to mint, except the merge function offers a list of token target addresses intended to be used to merge multiple token rewards.
``` js
function merge(uint256 nonce, address[] mineTokens) public returns (bool success);
```
#### hash
Public interface function hash, meant to be overridden in implementation to define hashing algorithm and validation. Returns the validated digest
``` js
``` solidity
function hash(uint256 nonce) public returns (bytes32 digest);
```
@ -178,7 +178,7 @@ function hash(uint256 nonce) public returns (bytes32 digest);
Internal interface function \_reward, meant to be overridden in implementation to calculate and allocate the reward amount. The reward amount must be returned by this method.
``` js
``` solidity
function _reward() internal returns (uint);
```
@ -186,7 +186,7 @@ function _reward() internal returns (uint);
Internal interface function \_newEpoch, meant to be overridden in implementation to define a cutpoint for mutating mining variables in preparation for the next phase of mine.
``` js
``` solidity
function _newEpoch(uint256 nonce) internal returns (uint);
```
@ -194,7 +194,7 @@ function _newEpoch(uint256 nonce) internal returns (uint);
Internal interface function \_adjustDifficulty, meant to be overridden in implementation to adjust the difficulty (via field difficulty) of the mining as required
``` js
``` solidity
function _adjustDifficulty() internal returns (uint);
```
@ -202,7 +202,7 @@ function _adjustDifficulty() internal returns (uint);
The amount of time, in seconds, between difficulty adjustment operations.
``` js
``` solidity
function getAdjustmentInterval() public view returns (uint);
```
@ -210,16 +210,15 @@ function getAdjustmentInterval() public view returns (uint);
Recent ethereum block hash, used to prevent pre-mining future blocks.
``` js
``` solidity
function getChallengeNumber() public view returns (bytes32);
```
#### getMiningDifficulty
The number of digits that the digest of the PoW solution requires which typically auto adjusts during reward generation.Return the current reward amount. Depending on the algorithm, typically rewards are divided every reward era as tokens are mined to provide scarcity.
The number of digits that the digest of the PoW solution requires which typically auto adjusts during reward generation.
``` js
``` solidity
function getMiningDifficulty() public view returns (uint)
```
@ -227,16 +226,20 @@ function getMiningDifficulty() public view returns (uint)
Return the current reward amount. Depending on the algorithm, typically rewards are divided every reward era as tokens are mined to provide scarcity.
``` js
``` solidity
function getMiningReward() public view returns (uint)
```
### Example mining function
A general mining function written in python for finding a valid nonce for mined token 0xbitcoin, is as follows:
```
A general mining function written in python for finding a valid nonce for keccak256 mined token, is as follows:
``` python
def generate_nonce():
myhex = b'%064x' % getrandbits(32*8)
return codecs.decode(myhex, 'hex_codec')
def mine(challenge, public_address, difficulty):
while True:
nonce = generate_random_number()
nonce = generate_nonce()
hash1 = int(sha3.keccak_256(challenge+public_address+nonce).hexdigest(), 16)
if hash1 < difficulty:
return nonce, hash1
@ -244,18 +247,214 @@ def mine(challenge, public_address, difficulty):
Once the nonce and hash1 are found, these are used to call the mint() function of the smart contract to receive a reward of tokens.
### Merged Mining Extension (Optional)
In order to provide support for merge mining multiple tokens, an optional merged mining extension can be implemented as part of the ERC918 standard. It is important to note that the following function will only properly work if the base contracts use tx.origin instead of msg.sender when applying rewards. If not the rewarded tokens will be sent to the calling contract and not the end user.
``` solidity
/**
* @title ERC-918 Mineable Token Standard, optional merged mining functionality
* @dev See https://github.com/ethereum/EIPs/blob/master/EIPS/eip-918.md
*
*/
contract ERC918Merged is AbstractERC918 {
/*
* @notice Externally facing merge function that is called by miners to validate challenge digests, calculate reward,
* populate statistics, mutate state variables and adjust the solution difficulty as required. Additionally, the
* merge function takes an array of target token addresses to be used in merged rewards. Once complete,
* a Mint event is emitted before returning a success indicator.
*
* @param _nonce the solution nonce
**/
function merge(uint256 _nonce, address[] _mineTokens) public returns (bool) {
for (uint i = 0; i < _mineTokens.length; i++) {
address tokenAddress = _mineTokens[i];
ERC918Interface(tokenAddress).mint(_nonce);
}
}
/*
* @notice Externally facing merge function kept for backwards compatability with previous definition
*
* @param _nonce the solution nonce
* @param _challenge_digest the keccak256 encoded challenge number + message sender + solution nonce
**/
function merge(uint256 _nonce, bytes32 _challenge_digest, address[] _mineTokens) public returns (bool) {
//the challenge digest must match the expected
bytes32 digest = keccak256( abi.encodePacked(challengeNumber, msg.sender, _nonce) );
require(digest == _challenge_digest, "Challenge digest does not match expected digest on token contract [ ERC918Merged.mint() ]");
return merge(_nonce, _mineTokens);
}
}
```
### Delegated Minting Extension (Optional)
In order to facilitate a third party minting submission paradigm, such as the case of miners submitting solutions to a pool operator and/or system, a delegated minting extension can be used to allow pool accounts submit solutions on the behalf of a user, so the miner can avoid directly paying Ethereum transaction costs. This is performed by an off chain mining account packaging and signing a standardized mint solution packet and sending it to a pool or 3rd party to be submitted.
The ERC918 Mineable Mint Packet Metadata should be prepared using following schema:
``` solidity
{
"title": "Mineable Mint Packet Metadata",
"type": "object",
"properties": {
"nonce": {
"type": "string",
"description": "Identifies the target solution nonce",
},
"origin": {
"type": "string",
"description": "Identifies the original user that mined the solution nonce",
},
"signature": {
"type": "string",
"description": "The signed hash of tightly packed variables sha3('delegatedMintHashing(uint256,address)')+nonce+origin_account",
}
}
}
```
The preparation of a mineable mint packet on a JavaScript client would appear as follows:
``` solidity
const ethUtil = require("ethereumjs-util")
function prepareDelegatedMintTxn(nonce, address, privateKey) {
var functionSig = web3.sha3("delegatedMintHashing(uint256,address)").substring(0,10)
var hashOf = "0x" + bytes4ToHex(functionSig) + uint256ToHex(nonce) +addressToHex(accounts[1])
var data = ethUtil.sha3(hashOf)
var signature = ethUtil.ecsign(data, new Buffer(privateKey, 'hex'))
var sig = ethUtil.toRpcSig(signature.v, signature.r, signature.s)
// prepare the mint packet
var packet = {}
packet.nonce = nonce;
packet.origin = address;
packet.signature = sig;
// deliver resulting JSON packet to pool or third party submitter
var mineableMintPacket = JSON.stringify(packet, null, 4)
/* todo: send mineableMintPacket to submitter */
}
```
Once the packet is prepared and formatted it can then be routed to a third party that will submit the transaction to the contract's delegatedMint() function, thereby paying for the transaction gas and receiving the resulting tokens. The pool/third party must then manually payback the minted tokens minus fees to the original minter.
The following code sample exemplifies third party packet relaying:
``` solidity
//received by minter
var mineableMintPacket = ...
var packet = JSON.parse(mineableMintPacket)
erc918MineableToken.delegatedMint(packet.nonce, packet.origin, packet.signature)
```
The Extension expands upon ERC918 realized here as a sub-contract:
``` js
contract ERC918DelegatedMint is AbstractERC918 {
/**
* @notice Hash (keccak256) of the payload used by delegatedMint
* @param _nonce the golden nonce
* @param _origin the original minter
* @param _signature the original minter's eliptical curve signature
*/
function delegatedMint(uint256 _nonce, address _origin, bytes _signature) public returns (bool success) {
bytes32 hashedTx = delegatedMintHashing(_nonce, _origin);
address minter = recover(hashedTx, _signature);
require(minter == _origin, "Origin minter address does not match recovered signature address [ AbstractERC918.delegatedMint() ]");
require(minter != address(0), "Invalid minter address recovered from signature [ ERC918DelegatedMint.delegatedMint() ]");
success = mintInternal(_nonce, minter);
}
/**
* @notice Hash (keccak256) of the payload used by delegatedMint
* @param _nonce the golden nonce
* @param _origin the original minter
*/
function delegatedMintHashing(uint256 _nonce, address _origin) internal pure returns (bytes32) {
/* "0xb548f23d": delegatedMintHashing(uint256,address) */
return keccak256( abi.encodePacked( bytes4(0xb548f23d), _nonce, _origin) );
}
}
```
### Mineable Token Metadata (Optional)
In order to provide for richer and potentially mutable metadata for a particular Mineable Token, it is more viable to offer an off-chain reference to said data. This requires the implementation of a single interface method 'metadataURI()' that returns a JSON string encoded with the string fields symbol, name, description, website, image, and type.
Solidity interface for Mineable Token Metadata:
``` solidity
/**
* @title ERC-918 Mineable Token Standard, optional metadata extension
* @dev See https://github.com/ethereum/EIPs/blob/master/EIPS/eip-918.md
*
*/
interface ERC918Metadata is AbstractERC918 {
/**
* @notice A distinct Uniform Resource Identifier (URI) for a mineable asset.
*/
function metadataURI() external view returns (string);
}
```
Mineable Token Metadata JSON schema definition:
``` solidity
{
"title": "Mineable Token Metadata",
"type": "object",
"properties": {
"symbol": {
"type": "string",
"description": "Identifies the Mineable Token's symbol",
},
"name": {
"type": "string",
"description": "Identifies the Mineable Token's name",
},
"description": {
"type": "string",
"description": "Identifies the Mineable Token's long description",
},
"website": {
"type": "string",
"description": "Identifies the Mineable Token's homepage URI",
},
"image": {
"type": "string",
"description": "Identifies the Mineable Token's image URI",
},
"type": {
"type": "string",
"description": "Identifies the Mineable Token's hash algorithm ( ie.keccak256 ) used to encode the solution",
}
}
}
```
### Rationale
A keccak256 algoritm does not have to be used, but it is recommended since it is a cost effective one-way algorithm to perform in the EVM and simple to perform in solidity. The nonce is the solution that miners try to find and so it is part of the hashing algorithm. A challengeNumber is also part of the hash so that future blocks cannot be mined since it acts like a random piece of data that is not revealed until a mining round starts. The msg.sender address is part of the hash so that a nonce solution is valid only for a particular Ethereum account and so the solution is not susceptible to man-in-the-middle attacks. This also allows pools to operate without being easily cheated by the miners since pools can force miners to mine using the pool's address in the hash algo.
The solidity keccak256 algorithm does not have to be used, but it is recommended since it is a cost effective one-way algorithm to perform in the EVM and simple to perform in solidity. The nonce is the solution that miners try to find and so it is part of the hashing algorithm. A challengeNumber is also part of the hash so that future blocks cannot be mined since it acts like a random piece of data that is not revealed until a mining round starts. The msg.sender address is part of the hash so that a nonce solution is valid only for a particular Ethereum account and so the solution is not susceptible to man-in-the-middle attacks. This also allows pools to operate without being easily cheated by the miners since pools can force miners to mine using the pool's address in the hash algorithm.
The economics of transferring electricity and hardware into mined token assets offers a flourishing community of decentralized miners the option to be involved in the Ethereum token economy directly. By voting with hashpower, an economically pegged asset to real-world resources, miners are incentivized to participate in early token trade to revamp initial costs, providing a bootstrapped stimulus mechanism between miners and early investors.
The economics of transferring electricity and hardware into mined token assets offers a flourishing community of decentralized miners the option to be involved in the Ethereum token economy directly. By voting with hash power, an economically pegged asset to real-world resources, miners are incentivized to participate in early token trade to revamp initial costs, providing a bootstrapped stimulus mechanism between miners and early investors.
One community concern for mined tokens has been around energy use without a function for securing a network. Although token mining does not secure a network, it serves the function of securing a community from corruption as it offers an alternative to centralized ICOs. Furthermore, an initial mining offering may last as little as a week, a day, or an hour at which point all of the tokens would have been minted.
### Backwards Compatibility
Earlier versions of this standard incorporated a redundant 'challenge_digest' parameter on the mint() function that hash-encoded the packed variables challengeNumber, msg.sender and nonce. It was decided that this could be removed from the standard to help minimize processing and thereby gas usage during mint operations. However, in the name of interoperability with existing mining programs and pool software the following contract can be added to the inheritance tree:
Backwards incompatibilities are not introduced.
``` solidity
/**
* @title ERC-918 Mineable Token Standard, optional backwards compatibility function
* @dev See https://github.com/ethereum/EIPs/blob/master/EIPS/eip-918.md
*
*/
contract ERC918BackwardsCompatible is AbstractERC918 {
/*
* @notice Externally facing mint function kept for backwards compatability with previous mint() definition
* @param _nonce the solution nonce
* @param _challenge_digest the keccak256 encoded challenge number + message sender + solution nonce
**/
function mint(uint256 _nonce, bytes32 _challenge_digest) public returns (bool success) {
//the challenge digest must match the expected
bytes32 digest = keccak256( abi.encodePacked(challengeNumber, msg.sender, _nonce) );
require(digest == _challenge_digest, "Challenge digest does not match expected digest on token contract [ AbstractERC918.mint() ]");
success = mint(_nonce);
}
}
```
### Test Cases
(Test cases for an implementation are mandatory for EIPs that are affecting consensus changes. Other EIPs can choose to include links to test cases if applicable.)
@ -284,3 +483,4 @@ https://etherscan.io/address/0x1a136ae98b49b92841562b6574d1f3f5b0044e4c
### Copyright
Copyright and related rights waived via [CC0](https://creativecommons.org/publicdomain/zero/1.0/).