一个非常赞的网站, https://cryptozombies.io/. 非常游戏化地带领你一步一步地写DApp.
3.10
If a view function is called internally from another function in the same contract that is not a view function, it will still cost gas. This is because the other function creates a transaction on Ethereum, and will still need to be verified from every node. So view functions are only free when they're called externally.
3.11
Storage很昂贵.
This is because every time you write or change a piece of data, it’s written permanently to the blockchain. Forever! Thousands of nodes across the world need to store that data on their hard drives, and this amount of data keeps growing over time as the blockchain grows. So there's a cost to doing that.
In order to keep costs down, you want to avoid writing data to storage except when absolutely necessary. Sometimes this involves seemingly inefficient programming logic — like rebuilding an array in memory
every time a function is called instead of simply saving that array in a variable for quick lookups.
3.12
uint[]
上删除一个元素, 就需要后面的元素都前移一位补空, 这是非常费gas的.
4.1 Payable
We have visibility modifiers that control when and where the function can be called from: private means it's only callable from other functions inside the contract; internal is like private but can also be called by contracts that inherit from this one; external can only be called outside the contract; and finally public can be called anywhere, both internally and externally.
We also have state modifiers, which tell us how the function interacts with the BlockChain: view tells us that by running the function, no data will be saved/changed. pure tells us that not only does the function not save any data to the blockchain, but it also doesn't read any data from the blockchain. Both of these don't cost any gas to call if they're called externally from outside the contract (but they do cost gas if called internally by another function).
Then we have custom modifiers
4.2 Withdraws
没看懂.
function withdraw() external onlyOwner {
owner.transfer(this.balance);
}
4.4 Random Number
In Ethereum, when you call a function on a contract, you broadcast it to a node or nodes on the network as a transaction. The nodes on the network then collect a bunch of transactions, try to be the first to solve a computationally-intensive mathematical problem as a "Proof of Work", and then publish that group of transactions along with their Proof of Work (PoW) as a block to the rest of the network.
Once a node has solved the PoW, the other nodes stop trying to solve the PoW, verify that the other node's list of transactions are valid, and then accept the block and move on to trying to solve the next block.
This makes our random number function exploitable.
Let's say we had a coin flip contract — heads you double your money, tails you lose everything. Let's say it used the above random function to determine heads or tails. (random >= 50 is heads, random < 50 is tails).
If I were running a node, I could publish a transaction only to my own node and not share it. I could then run the coin flip function to see if I won — and if I lost, choose not to include that transaction in the next block I'm solving. I could keep doing this indefinitely until I finally won the coin flip and solved the next block, and profit.
5. ERC721 & Crypto-Collectibles
5.1 Tokens on Ethereum
ERC721 token适合用来做商品. 因为它的每一个token都是不同的, 有独立的ID, 也无法分割.
5.10 SafeMath Part 2
assert
is similar to require
, where it will throw an error if false. The difference between assert
and require
is that require
will refund the user the rest of their gas when a function fails, whereas assert
will not. So most of the time you want to use require
in your code; assert
is typically used when something has gone horribly wrong with the code (like a uint overflow).