從 Solidity 文件中了解 TokenCreator/OwnedToken 範例
這是包含範例https://solidity.readthedocs.io的頁面
這是兩個應該一起工作的契約(我的問題如下):
這就是我認為它的工作原理。在我嘗試引導您完成時,請更正我的步驟。
- 由於每個地址一個合約,這兩個合約被部署到兩個不同的地址。
- 在OwnedToken合約創建者變數的建構子中,分配了一個位於msg.sender地址的合約。通過這個變數,就可以訪問該合約的功能。這讓我覺得這個合約的創建者一定是另一個合約(TokenCreator)
- 然後我查看TokenCreator合約的程式碼,以找出哪個函式負責創建OwnedToken合約。我在第 43 行找到它。
- 現在我難住了。new OwnedToken(name)是如何工作的?TokenCreator合約如何看到OwnedToken?
另外我剛剛發現了一個編譯器錯誤:
犁過所有這些東西真是太令人興奮了!謝謝你,你真棒!
將發現錯誤的程式碼替換為:
function changeName(bytes32 newName) { // Only the creator can alter the name -- // the comparison is possible since contracts // are implicitly convertible to addresses. if (msg.sender == address(creator)) name = newName; }
它將在Solidity Online Compiler和
solc
編譯器中通過geth
.Q1由於每個地址一個合約,這兩個合約被部署到兩個不同的地址。
您可以分別編譯和部署這兩個合約——這需要對程式碼進行一些更改。請參閱如何在硬分叉後有條件地將乙太幣發送到另一個帳戶以保護自己免受重放攻擊中的地址引用
ClassicCheck contract
的合約。SafeConditionalHFTransfer``ClassicCheck
但是這個例子是為了讓你一起編譯它們而編寫的。您部署
TokenCreator
到契約地址。當您呼叫
TokenCreator.createToken(...)
時,它將創建一個新OwnedToken(...)
合約並返回合約地址。您必須儲存此地址,因為TokenCreator
合約不儲存它。Q2在 OwnedToken 合約創建者變數的建構子中,分配了一個位於 msg.sender 地址的合約。通過這個變數,就可以訪問該合約的功能。這讓我覺得這個合約的創建者一定是另一個合約(TokenCreator)
是的。
Q3然後我查看 TokenCreator 合約的程式碼,以找出哪個函式負責創建 OwnedToken 合約。我在第 43 行找到它。
創建
OwnedToken
合約的是#50。Q4現在我被難住了。new OwnedToken(name) 是如何工作的?TokenCreator 合約如何看到 OwnedToken?
new OwnedToken(name)
創建新OwnedToken
合約。然後該createToken(...)
函式返回OwnedToken(...)
已部署到的地址。筆記
範常式式碼存在問題,因為非常量函式無法輕鬆返回值。您必須生成一個事件來顯示令牌創建地址。請參閱如何獲取非常量事務函式返回的值?更多細節。
或者您可以修改
TokenCreator
合約以儲存創建的合約地址,如呼叫帶參數的函式時如何獲取返回值?結果由answer.getNumResult("idOne")
常量函式儲存和訪問。
TokenCreator
不儲存createToken(...)
呼叫的返回值,因此不知道OwnedToken
已部署到哪裡。當您致電時
changeName(...)
,您必須提供OwnedToken
已部署到的地址。讓我們進行修改
TokenCreator
以進行測試執行這是保存在以下位置的修改後的
TokenCreator
契約TokenCreator.sol
:contract OwnedToken { // TokenCreator is a contract type that is defined below. // It is fine to reference it as long as it is not used // to create a new contract. TokenCreator public creator; address public owner; string public name; // This is the constructor which registers the // creator and the assigned name. function OwnedToken(string _name) { owner = msg.sender; // We do an explicit type conversion from `address` // to `TokenCreator` and assume that the type of // the calling contract is TokenCreator, there is // no real way to check that. creator = TokenCreator(msg.sender); name = _name; } function changeName(string newName) { // Only the creator can alter the name -- // the comparison is possible since contracts // are implicitly convertible to addresses. if (msg.sender == address(creator)) name = newName; } function transfer(address newOwner) { // Only the current owner can transfer the token. if (msg.sender != owner) return; // We also want to ask the creator if the transfer // is fine. Note that this calls a function of the // contract defined below. If the call fails (e.g. // due to out-of-gas), the execution here stops // immediately. if (creator.isTokenTransferOK(owner, newOwner)) owner = newOwner; } } contract TokenCreator { mapping(string => address) addresses; function getAddress(string name) constant returns (address) { return addresses[name]; } function createToken(string name) returns (OwnedToken tokenAddress) { // Create a new Token contract and return its address. // From the JavaScript side, the return type is simply // "address", as this is the closest type available in // the ABI. tokenAddress = new OwnedToken(name); addresses[name] = tokenAddress; } function changeName(string oldName, string newName) { // Again, the external type of "tokenAddress" is // simply "address". address tokenAddress = addresses[oldName]; delete addresses[oldName]; addresses[newName] = tokenAddress; OwnedToken(tokenAddress).changeName(newName); } function isTokenTransferOK( address currentOwner, address newOwner ) returns (bool ok) { // Check some arbitrary condition. address tokenAddress = msg.sender; return (sha3(newOwner) & 0xff) == (bytes20(tokenAddress) & 0xff); } }
使用How to load Solidity source file into geth
stripCrLf
中的腳本,我將原始碼扁平化為:user@Kumquat:~$ echo "var tokenCreatorSource='`stripCrLf TokenCreator.sol`'" var tokenCreatorSource='contract OwnedToken { TokenCreator public creator; address public owner; string public name; function OwnedToken(string _name) { owner = msg.sender; creator = TokenCreator(msg.sender); name = _name; } function changeName(string newName) { if (msg.sender == address(creator)) name = newName; } function transfer(address newOwner) { if (msg.sender != owner) return; if (creator.isTokenTransferOK(owner, newOwner)) owner = newOwner; }}contract TokenCreator { mapping(string => address) addresses; function getAddress(string name) constant returns (address) { return addresses[name]; } function createToken(string name) returns (OwnedToken tokenAddress) { tokenAddress = new OwnedToken(name); addresses[name] = tokenAddress; } function changeName(string oldName, string newName) { address tokenAddress = addresses[oldName]; delete addresses[oldName]; addresses[newName] = tokenAddress; OwnedToken(tokenAddress).changeName(newName); } function isTokenTransferOK( address currentOwner, address newOwner ) returns (bool ok) { address tokenAddress = msg.sender; return (sha3(newOwner) & 0xff) == (bytes20(tokenAddress) & 0xff); }}'
我正在使用以下命令執行開發網路(我的密碼在
passwordfile
):geth --datadir ~/devdata --dev --mine --minerthreads 1 --unlock 0 --password ~/passwordfile console
我將扁平化程式碼粘貼到
geth
命令行中:> var tokenCreatorSource='contract OwnedToken { TokenCreator public creator; address public owner; string public name; function OwnedToken(string _name) { owner = msg.sender; creator = TokenCreator(msg.sender); name = _name; } function changeName(string newName) { if (msg.sender == address(creator)) name = newName; } function transfer(address newOwner) { if (msg.sender != owner) return; if (creator.isTokenTransferOK(owner, newOwner)) owner = newOwner; }}contract TokenCreator { mapping(string => address) addresses; function getAddress(string name) constant returns (address) { return addresses[name]; } function createToken(string name) returns (OwnedToken tokenAddress) { tokenAddress = new OwnedToken(name); addresses[name] = tokenAddress; } function changeName(string oldName, string newName) { address tokenAddress = addresses[oldName]; delete addresses[oldName]; addresses[newName] = tokenAddress; OwnedToken(tokenAddress).changeName(newName); } function isTokenTransferOK( address currentOwner, address newOwner ) returns (bool ok) { address tokenAddress = msg.sender; return (sha3(newOwner) & 0xff) == (bytes20(tokenAddress) & 0xff); }}'
並使用以下命令編譯程式碼:
> var tokenCreatorCompiled = web3.eth.compile.solidity(tokenCreatorSource); Version: 0.3.5-0/RelWithDebInfo-Linux/g++/Interpreter path: /usr/bin/solc undefined
可以看到生成的 ABI:
> tokenCreatorCompiled.TokenCreator.info.abiDefinition [{ constant: false, inputs: [{ name: "name", type: "string" }], name: "createToken", outputs: [{ name: "tokenAddress", type: "address" }], type: "function" }, { constant: false, inputs: [{ name: "oldName", type: "string" }, { name: "newName", type: "string" }], name: "changeName", outputs: [], type: "function" }, { constant: true, inputs: [{ name: "name", type: "string" }], name: "getAddress", outputs: [{ name: "", type: "address" }], type: "function" }, { constant: false, inputs: [{ name: "currentOwner", type: "address" }, { name: "newOwner", type: "address" }], name: "isTokenTransferOK", outputs: [{ name: "ok", type: "bool" }], type: "function" }] > tokenCreatorCompiled.OwnedToken.info.abiDefinition [{ constant: true, inputs: [], name: "creator", outputs: [{ name: "", type: "address" }], type: "function" }, { constant: true, inputs: [], name: "name", outputs: [{ name: "", type: "string" }], type: "function" }, { constant: false, inputs: [{ name: "newOwner", type: "address" }], name: "transfer", outputs: [], type: "function" }, { constant: false, inputs: [{ name: "newName", type: "string" }], name: "changeName", outputs: [], type: "function" }, { constant: true, inputs: [], name: "owner", outputs: [{ name: "", type: "address" }], type: "function" }, { inputs: [{ name: "_name", type: "string" }], type: "constructor" }]
在區塊鏈上創建合約:
> var tokenCreatorContract = web3.eth.contract(tokenCreatorCompiled.TokenCreator.info.abiDefinition); undefined > var tokenCreator = tokenCreatorContract.new({ from:web3.eth.accounts[0], data: tokenCreatorCompiled.TokenCreator.code, gas: 1000000}, function(e, contract) { if (!e) { if (!contract.address) { console.log("Contract transaction send: TransactionHash: " + contract.transactionHash + " waiting to be mined..."); } else { console.log("Contract mined! Address: " + contract.address); console.log(contract); } } }) ... Contract mined! Address: 0xfdb30244a9d9b8e98e9dd57ac81728725830f54b
BokkyPooBahToken
使用以下命令創建:> tokenCreator.createToken("BokkyPooBahToken", {from:eth.accounts[0]}) "0xc55cc14b02bd0ca783dc7457bd5f09263fb5750135e7f7e4e2c070f6dd855785"
讓我們查看創建的令牌的地址:
> var tokenAddress = tokenCreator.getAddress("BokkyPooBahToken") > tokenAddress "0xcd347e1c299b02bba605f74e06031e7d170a1aed"
讓我們查看創建的令牌詳細資訊:
> var token = eth.contract(tokenCreatorCompiled.OwnedToken.info.abiDefinition).at(tokenAddress); undefined > token.owner() "0xfdb30244a9d9b8e98e9dd57ac81728725830f54b" // Above is the TokenCreator contract address > token.name() "BokkyPooBahToken"
讓我們更改令牌的名稱:
> tokenCreator.changeName("BokkyPooBahToken", "BoppyKooBahToken", {from: eth.accounts[0]}) "0xa68045d36f313bad2abed292e86729ac9cf94c12a368b4d73a78f4a2826edf32" > token.name() "BoppyKooBahToken"