Solidity 关于References和 Mapping的一个坑

张亚宁   |     |   860 次阅读

Solidity 关于References和 Mapping的一个坑

判断一下Sample是否会正确更新doOnce

contract Sample {  
  mapping (uint => bool) doOnce;    
  uint _actionNumber;

  function() {  
     var a = doOnce[_actionNumber];
     if (a == true) { throw; }
     a = true;

     _actionNumber++;
 }

 function get(uint i) return (bool b){
     b = doOnce[i];
 }
}

编译sol

$ solc_helper Sample.sol 

======= Sample =======
Gas estimation:
construction:
   42 + 12000 = 12042
external:
   fallback:    20332
internal:
   ():  [???]


-------------------------------------
Enter Gas: 
300000
Enter Value To Be Transferred: 

Enter Input: 

loadScript('/Users/u2/cryptape/ethereum-bootstrap/Sample_compiled.js')

在geth中加载

> loadScript('/Users/u2/cryptape/ethereum-bootstrap/Sample_compiled.js')
null
I0824 10:01:31.023238 eth/api.go:1191] Tx(0xb2d1de4cfb6ab1f9eecf9a086b9c7d311051186d60c3856032c3bfb5ffd41794) created: 0xadff100480afd5e6eb6ccc062872cb37cebeb786
Contract transaction send: TransactionHash: 0xb2d1de4cfb6ab1f9eecf9a086b9c7d311051186d60c3856032c3bfb5ffd41794 waiting to be mined...
Compiled Object : SampleCompiled
Contract : SampleContract
Contract Instance : Sample
true
> I0824 10:01:38.891388 miner/miner.go:119] Starting mining operation (CPU=4 TOT=5)
I0824 10:01:38.892233 miner/worker.go:573] commit new work on block 381 with 2 txs & 1 uncles. Took 809.825µs
I0824 10:01:38.918238 miner/worker.go:339] 🔨  Mined block (#381 / 063f834c). Wait 5 blocks for confirmation

测试下:

> Sample
{
  abi: [{
      constant: false,
      inputs: [{...}],
      name: "get",
      outputs: [{...}],
      type: "function"
  }],
  address: "0xadff100480afd5e6eb6ccc062872cb37cebeb786",
  transactionHash: "0xb2d1de4cfb6ab1f9eecf9a086b9c7d311051186d60c3856032c3bfb5ffd41794",
  allEvents: function(),
  get: function()
}
> Sample.get.call(1)
false
> Sample.get.call(0)
false
> web3.eth.sendTransaction({from: web3.eth.accounts[0],to: Sample.address})
I0824 10:03:18.703757 eth/api.go:1193] Tx(0x9ab493c551ec66c1eb262920b856f75f32690c4fb76175890ad63598833f6c31) to: 0xadff100480afd5e6eb6ccc062872cb37cebeb786
"0x9ab493c551ec66c1eb262920b856f75f32690c4fb76175890ad63598833f6c31"
> Sample.get.call(0)
false
> Sample.get.call(1)
false

保存bool失败

更新后doOnce

contract Sample {  
  struct info { bool doOnce; }
  mapping (uint => info) infoMap;    
  uint _actionNumber;

  function() {
     var a = infoMap[_actionNumber];
     if (a.doOnce == true) { throw; }
     a.doOnce = true;

     _actionNumber++;

 }
 function get(uint i) returns (bool b){
     var a = infoMap[i];
     b = a.doOnce;  
 }
}
$ solc_helper Sample.sol 

======= Sample =======
Gas estimation:
construction:
   57 + 26600 = 26657
external:
   get(uint256):    40412
   fallback:    40471
internal:
   ():  [???]


-------------------------------------
Enter Gas: 
400000
Enter Value To Be Transferred: 

Enter Input: 

loadScript('/Users/u2/cryptape/ethereum-bootstrap/Sample_compiled.js')
> loadScript('/Users/u2/cryptape/ethereum-bootstrap/Sample_compiled.js')
null
I0824 10:13:05.568238 eth/api.go:1191] Tx(0x77e7e8a347bff1b39e44b6873b6eda4b683e066ec24e8c112cfc7d6603fedf47) created: 0x9b850aa0a0e3b982d1f1cd6b86284eda8288337e
Contract transaction send: TransactionHash: 0x77e7e8a347bff1b39e44b6873b6eda4b683e066ec24e8c112cfc7d6603fedf47 waiting to be mined...
Compiled Object : SampleCompiled
Contract : SampleContract
Contract Instance : Sample
true
> Sample
{
  abi: [{
      constant: false,
      inputs: [{...}],
      name: "get",
      outputs: [{...}],
      type: "function"
  }],
  address: "0x9b850aa0a0e3b982d1f1cd6b86284eda8288337e",
  transactionHash: "0x77e7e8a347bff1b39e44b6873b6eda4b683e066ec24e8c112cfc7d6603fedf47",
  allEvents: function(),
  get: function()
}
> web3.eth.sendTransaction({from: web3.eth.accounts[0], to: Sample.address})
I0824 10:14:10.042082 eth/api.go:1193] Tx(0x4b92674cca27f9fac042cea3fcdecb946e032de831443185cdd5975dc5cd511d) to: 0x9b850aa0a0e3b982d1f1cd6b86284eda8288337e
"0x4b92674cca27f9fac042cea3fcdecb946e032de831443185cdd5975dc5cd511d"
> web3.eth.sendTransaction({from: web3.eth.accounts[0], to: Sample.address})
I0824 10:14:22.123947 eth/api.go:1193] Tx(0x200e9ad61ce1bff0344935ae6baa8ebdfb0a217e1bfd1bd2a0f86ea6914c3470) to: 0x9b850aa0a0e3b982d1f1cd6b86284eda8288337e
"0x200e9ad61ce1bff0344935ae6baa8ebdfb0a217e1bfd1bd2a0f86ea6914c3470"
> Sample.get.call(0)
true
> Sample.get.call(1)
false

> web3.eth.sendTransaction({from: web3.eth.accounts[0], to: Sample.address})

> Sample.get.call(1)
true

另外在某些情况下Geth和TestRPC是不同的:
https://github.com/u2/ether-router/blob/master/test/list.js
https://github.com/u2/ether-router/blob/master/test/sample.js

Sample的测试情况是Geth和TestRPC是一致的。
但是List的Geth和TestRPC是不一致的

> List.getAll.call(0)
[]


> List.setList.sendTransaction(0,[1,2,3],{from: web3.eth.accounts[0]})
I0824 10:56:29.761988 eth/api.go:1193] Tx(0x0ada2217b60f6ee69a0de3f1ea0d8c6d0858c228c9a543efe3e0a5bc3597171f) to: 0xd4f3bd8466d1b8e326db1fbf13505b3869e1083d
"0x0ada2217b60f6ee69a0de3f1ea0d8c6d0858c228c9a543efe3e0a5bc3597171f"


> web3.eth.getTransaction('0x0ada2217b60f6ee69a0de3f1ea0d8c6d0858c228c9a543efe3e0a5bc3597171f')
{
  blockHash: "0x16969fec496c7507c788d799c70227a622b5ec0ab30ff7d55acd1c590a45cbb5",
  blockNumber: 429,
  from: "0x7d1ca639d49cf648a97ebb630564abb5c9bd75ec",
  gas: 90000,
  gasPrice: 20000000000,
  hash: "0x0ada2217b60f6ee69a0de3f1ea0d8c6d0858c228c9a543efe3e0a5bc3597171f",
  input: "0xb8c58128000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000003",
  nonce: 36,
  to: "0xd4f3bd8466d1b8e326db1fbf13505b3869e1083d",
  transactionIndex: 0,
  value: 0
}

> List.getAll.call(0)
[]

链接:
Solidity Frustrations: References and Mapping