Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
G
Geth-Modification
Project
Project
Details
Activity
Releases
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
张蕾
Geth-Modification
Commits
5a0e7517
Commit
5a0e7517
authored
Jun 16, 2014
by
obscuren
Browse files
Options
Browse Files
Download
Plain Diff
Merge branch 'release/0.5.13'
parents
006ac772
ff0f15f7
Changes
27
Show whitespace changes
Inline
Side-by-side
Showing
27 changed files
with
1271 additions
and
352 deletions
+1271
-352
README.md
README.md
+1
-1
asm.go
ethchain/asm.go
+3
-9
block.go
ethchain/block.go
+30
-0
block_chain.go
ethchain/block_chain.go
+4
-15
closure.go
ethchain/closure.go
+14
-12
deprecated.go
ethchain/deprecated.go
+236
-0
error.go
ethchain/error.go
+35
-0
fees.go
ethchain/fees.go
+0
-24
stack.go
ethchain/stack.go
+6
-0
state.go
ethchain/state.go
+134
-39
state_manager.go
ethchain/state_manager.go
+36
-120
state_object.go
ethchain/state_object.go
+68
-6
state_transition.go
ethchain/state_transition.go
+260
-0
transaction.go
ethchain/transaction.go
+14
-8
transaction_pool.go
ethchain/transaction_pool.go
+33
-11
types.go
ethchain/types.go
+37
-16
vm.go
ethchain/vm.go
+111
-55
miner.go
ethminer/miner.go
+13
-2
pub.go
ethpub/pub.go
+6
-4
types.go
ethpub/types.go
+8
-5
big.go
ethutil/big.go
+2
-2
common.go
ethutil/common.go
+2
-2
config.go
ethutil/config.go
+31
-8
keypair.go
ethutil/keypair.go
+6
-0
rlp.go
ethutil/rlp.go
+1
-0
messaging.go
ethwire/messaging.go
+159
-4
peer.go
peer.go
+21
-9
No files found.
README.md
View file @
5a0e7517
...
...
@@ -6,7 +6,7 @@ Ethereum
Ethereum Go Development package (C) Jeffrey Wilcke
Ethereum is currently in its testing phase. The current state is "Proof
of Concept 5.0 RC1
2
". For build instructions see the
[
Wiki
](
https://github.com/ethereum/go-ethereum/wiki/Building-Ethereum(Go
)
).
of Concept 5.0 RC1
3
". For build instructions see the
[
Wiki
](
https://github.com/ethereum/go-ethereum/wiki/Building-Ethereum(Go
)
).
Ethereum Go is split up in several sub packages Please refer to each
individual package for more information.
...
...
ethchain/asm.go
View file @
5a0e7517
...
...
@@ -25,16 +25,10 @@ func Disassemble(script []byte) (asm []string) {
pc
.
Add
(
pc
,
ethutil
.
Big1
)
a
:=
int64
(
op
)
-
int64
(
PUSH1
)
+
1
data
:=
script
[
pc
.
Int64
()
:
pc
.
Int64
()
+
a
]
val
:=
ethutil
.
BigD
(
data
)
var
b
[]
byte
if
val
.
Int64
()
==
0
{
b
=
[]
byte
{
0
}
}
else
{
b
=
val
.
Bytes
()
if
len
(
data
)
==
0
{
data
=
[]
byte
{
0
}
}
asm
=
append
(
asm
,
fmt
.
Sprintf
(
"0x%x"
,
b
))
asm
=
append
(
asm
,
fmt
.
Sprintf
(
"%#x"
,
data
))
pc
.
Add
(
pc
,
big
.
NewInt
(
a
-
1
))
}
...
...
ethchain/block.go
View file @
5a0e7517
...
...
@@ -154,6 +154,36 @@ func (block *Block) PayFee(addr []byte, fee *big.Int) bool {
return
true
}
func
(
block
*
Block
)
CalcGasLimit
(
parent
*
Block
)
*
big
.
Int
{
if
block
.
Number
.
Cmp
(
big
.
NewInt
(
0
))
==
0
{
return
ethutil
.
BigPow
(
10
,
6
)
}
previous
:=
new
(
big
.
Int
)
.
Mul
(
big
.
NewInt
(
1023
),
parent
.
GasLimit
)
current
:=
new
(
big
.
Rat
)
.
Mul
(
new
(
big
.
Rat
)
.
SetInt
(
block
.
GasUsed
),
big
.
NewRat
(
6
,
5
))
curInt
:=
new
(
big
.
Int
)
.
Div
(
current
.
Num
(),
current
.
Denom
())
result
:=
new
(
big
.
Int
)
.
Add
(
previous
,
curInt
)
result
.
Div
(
result
,
big
.
NewInt
(
1024
))
min
:=
ethutil
.
BigPow
(
10
,
4
)
return
ethutil
.
BigMax
(
min
,
result
)
/*
base := new(big.Int)
base2 := new(big.Int)
parentGL := bc.CurrentBlock.GasLimit
parentUsed := bc.CurrentBlock.GasUsed
base.Mul(parentGL, big.NewInt(1024-1))
base2.Mul(parentUsed, big.NewInt(6))
base2.Div(base2, big.NewInt(5))
base.Add(base, base2)
base.Div(base, big.NewInt(1024))
*/
}
func
(
block
*
Block
)
BlockInfo
()
BlockInfo
{
bi
:=
BlockInfo
{}
data
,
_
:=
ethutil
.
Config
.
Db
.
Get
(
append
(
block
.
Hash
(),
[]
byte
(
"Info"
)
...
))
...
...
ethchain/block_chain.go
View file @
5a0e7517
...
...
@@ -55,6 +55,8 @@ func (bc *BlockChain) NewBlock(coinbase []byte) *Block {
nil
,
""
)
block
.
MinGasPrice
=
big
.
NewInt
(
10000000000000
)
if
bc
.
CurrentBlock
!=
nil
{
var
mul
*
big
.
Int
if
block
.
Time
<
lastBlockTime
+
42
{
...
...
@@ -72,19 +74,7 @@ func (bc *BlockChain) NewBlock(coinbase []byte) *Block {
block
.
Number
=
new
(
big
.
Int
)
.
Add
(
bc
.
CurrentBlock
.
Number
,
ethutil
.
Big1
)
// max(10000, (parent gas limit * (1024 - 1) + (parent gas used * 6 / 5)) / 1024)
base
:=
new
(
big
.
Int
)
base2
:=
new
(
big
.
Int
)
parentGL
:=
bc
.
CurrentBlock
.
GasLimit
parentUsed
:=
bc
.
CurrentBlock
.
GasUsed
base
.
Mul
(
parentGL
,
big
.
NewInt
(
1024
-
1
))
base2
.
Mul
(
parentUsed
,
big
.
NewInt
(
6
))
base2
.
Div
(
base2
,
big
.
NewInt
(
5
))
base
.
Add
(
base
,
base2
)
base
.
Div
(
base
,
big
.
NewInt
(
1024
))
block
.
GasLimit
=
ethutil
.
BigMax
(
big
.
NewInt
(
10000
),
base
)
block
.
GasLimit
=
block
.
CalcGasLimit
(
bc
.
CurrentBlock
)
}
return
block
...
...
@@ -271,7 +261,7 @@ func (bc *BlockChain) GetChain(hash []byte, amount int) []*Block {
func
AddTestNetFunds
(
block
*
Block
)
{
for
_
,
addr
:=
range
[]
string
{
"
8a40bfaa73256b60764c1bf40675a99083efb075
"
,
"
51ba59315b3a95761d0863b05ccc7a7f54703d99
"
,
"e4157b34ea9615cfbde6b4fda419828124b70c78"
,
"1e12515ce3e0f817a4ddef9ca55788a1d66bd2df"
,
"6c386a4b26f73c802f34673f7248bb118f97424a"
,
...
...
@@ -285,7 +275,6 @@ func AddTestNetFunds(block *Block) {
account
.
Amount
=
ethutil
.
Big
(
"1606938044258990275541962092341162602522202993782792835301376"
)
//ethutil.BigPow(2, 200)
block
.
state
.
UpdateStateObject
(
account
)
}
log
.
Printf
(
"%x
\n
"
,
block
.
RlpEncode
())
}
func
(
bc
*
BlockChain
)
setLastBlock
()
{
...
...
ethchain/closure.go
View file @
5a0e7517
...
...
@@ -17,7 +17,7 @@ type ClosureRef interface {
// Basic inline closure object which implement the 'closure' interface
type
Closure
struct
{
calle
e
ClosureRef
calle
r
ClosureRef
object
*
StateObject
Script
[]
byte
State
*
State
...
...
@@ -28,12 +28,14 @@ type Closure struct {
}
// Create a new closure for the given data items
func
NewClosure
(
calle
e
ClosureRef
,
object
*
StateObject
,
script
[]
byte
,
state
*
State
,
gas
,
price
*
big
.
Int
)
*
Closure
{
c
:=
&
Closure
{
calle
e
:
callee
,
object
:
object
,
Script
:
script
,
State
:
state
,
Args
:
nil
}
func
NewClosure
(
calle
r
ClosureRef
,
object
*
StateObject
,
script
[]
byte
,
state
*
State
,
gas
,
price
*
big
.
Int
)
*
Closure
{
c
:=
&
Closure
{
calle
r
:
caller
,
object
:
object
,
Script
:
script
,
State
:
state
,
Args
:
nil
}
// In most cases gas, price and value are pointers to transaction objects
// Gas should be a pointer so it can safely be reduced through the run
// This pointer will be off the state transition
c
.
Gas
=
gas
//new(big.Int).Set(gas)
// In most cases price and value are pointers to transaction objects
// and we don't want the transaction's values to change.
c
.
Gas
=
new
(
big
.
Int
)
.
Set
(
gas
)
c
.
Price
=
new
(
big
.
Int
)
.
Set
(
price
)
c
.
UsedGas
=
new
(
big
.
Int
)
...
...
@@ -83,11 +85,11 @@ func (c *Closure) Call(vm *Vm, args []byte, hook DebugHook) ([]byte, *big.Int, e
}
func
(
c
*
Closure
)
Return
(
ret
[]
byte
)
[]
byte
{
// Return the remaining gas to the calle
e
// If no calle
e
is present return it to
// Return the remaining gas to the calle
r
// If no calle
r
is present return it to
// the origin (i.e. contract or tx)
if
c
.
calle
e
!=
nil
{
c
.
calle
e
.
ReturnGas
(
c
.
Gas
,
c
.
Price
,
c
.
State
)
if
c
.
calle
r
!=
nil
{
c
.
calle
r
.
ReturnGas
(
c
.
Gas
,
c
.
Price
,
c
.
State
)
}
else
{
c
.
object
.
ReturnGas
(
c
.
Gas
,
c
.
Price
,
c
.
State
)
}
...
...
@@ -107,7 +109,7 @@ func (c *Closure) UseGas(gas *big.Int) bool {
return
true
}
// Implement the
Callee
interface
// Implement the
caller
interface
func
(
c
*
Closure
)
ReturnGas
(
gas
,
price
*
big
.
Int
,
state
*
State
)
{
// Return the gas to the closure
c
.
Gas
.
Add
(
c
.
Gas
,
gas
)
...
...
@@ -118,8 +120,8 @@ func (c *Closure) Object() *StateObject {
return
c
.
object
}
func
(
c
*
Closure
)
Calle
e
()
ClosureRef
{
return
c
.
calle
e
func
(
c
*
Closure
)
Calle
r
()
ClosureRef
{
return
c
.
calle
r
}
func
(
c
*
Closure
)
N
()
*
big
.
Int
{
...
...
ethchain/deprecated.go
0 → 100644
View file @
5a0e7517
package
ethchain
import
(
"bytes"
"fmt"
"github.com/ethereum/eth-go/ethutil"
"math/big"
)
func
(
sm
*
StateManager
)
MakeStateObject
(
state
*
State
,
tx
*
Transaction
)
*
StateObject
{
contract
:=
MakeContract
(
tx
,
state
)
if
contract
!=
nil
{
state
.
states
[
string
(
tx
.
CreationAddress
())]
=
contract
.
state
return
contract
}
return
nil
}
func
(
sm
*
StateManager
)
EvalScript
(
state
*
State
,
script
[]
byte
,
object
*
StateObject
,
tx
*
Transaction
,
block
*
Block
)
(
ret
[]
byte
,
gas
*
big
.
Int
,
err
error
)
{
account
:=
state
.
GetAccount
(
tx
.
Sender
())
err
=
account
.
ConvertGas
(
tx
.
Gas
,
tx
.
GasPrice
)
if
err
!=
nil
{
ethutil
.
Config
.
Log
.
Debugln
(
err
)
return
}
closure
:=
NewClosure
(
account
,
object
,
script
,
state
,
tx
.
Gas
,
tx
.
GasPrice
)
vm
:=
NewVm
(
state
,
sm
,
RuntimeVars
{
Origin
:
account
.
Address
(),
BlockNumber
:
block
.
BlockInfo
()
.
Number
,
PrevHash
:
block
.
PrevHash
,
Coinbase
:
block
.
Coinbase
,
Time
:
block
.
Time
,
Diff
:
block
.
Difficulty
,
Value
:
tx
.
Value
,
//Price: tx.GasPrice,
})
ret
,
gas
,
err
=
closure
.
Call
(
vm
,
tx
.
Data
,
nil
)
// Update the account (refunds)
state
.
UpdateStateObject
(
account
)
state
.
UpdateStateObject
(
object
)
return
}
func
(
self
*
StateManager
)
ProcessTransaction
(
tx
*
Transaction
,
coinbase
*
StateObject
,
state
*
State
,
toContract
bool
)
(
gas
*
big
.
Int
,
err
error
)
{
fmt
.
Printf
(
"state root before update %x
\n
"
,
state
.
Root
())
defer
func
()
{
if
r
:=
recover
();
r
!=
nil
{
ethutil
.
Config
.
Log
.
Infoln
(
r
)
err
=
fmt
.
Errorf
(
"%v"
,
r
)
}
}()
gas
=
new
(
big
.
Int
)
addGas
:=
func
(
g
*
big
.
Int
)
{
gas
.
Add
(
gas
,
g
)
}
addGas
(
GasTx
)
// Get the sender
sender
:=
state
.
GetAccount
(
tx
.
Sender
())
if
sender
.
Nonce
!=
tx
.
Nonce
{
err
=
NonceError
(
tx
.
Nonce
,
sender
.
Nonce
)
return
}
sender
.
Nonce
+=
1
defer
func
()
{
//state.UpdateStateObject(sender)
// Notify all subscribers
self
.
Ethereum
.
Reactor
()
.
Post
(
"newTx:post"
,
tx
)
}()
txTotalBytes
:=
big
.
NewInt
(
int64
(
len
(
tx
.
Data
)))
//fmt.Println("txTotalBytes", txTotalBytes)
//txTotalBytes.Div(txTotalBytes, ethutil.Big32)
addGas
(
new
(
big
.
Int
)
.
Mul
(
txTotalBytes
,
GasData
))
rGas
:=
new
(
big
.
Int
)
.
Set
(
gas
)
rGas
.
Mul
(
gas
,
tx
.
GasPrice
)
// Make sure there's enough in the sender's account. Having insufficient
// funds won't invalidate this transaction but simple ignores it.
totAmount
:=
new
(
big
.
Int
)
.
Add
(
tx
.
Value
,
rGas
)
if
sender
.
Amount
.
Cmp
(
totAmount
)
<
0
{
state
.
UpdateStateObject
(
sender
)
err
=
fmt
.
Errorf
(
"[TXPL] Insufficient amount in sender's (%x) account"
,
tx
.
Sender
())
return
}
coinbase
.
BuyGas
(
gas
,
tx
.
GasPrice
)
state
.
UpdateStateObject
(
coinbase
)
fmt
.
Printf
(
"1. root %x
\n
"
,
state
.
Root
())
// Get the receiver
receiver
:=
state
.
GetAccount
(
tx
.
Recipient
)
// Send Tx to self
if
bytes
.
Compare
(
tx
.
Recipient
,
tx
.
Sender
())
==
0
{
// Subtract the fee
sender
.
SubAmount
(
rGas
)
}
else
{
// Subtract the amount from the senders account
sender
.
SubAmount
(
totAmount
)
state
.
UpdateStateObject
(
sender
)
fmt
.
Printf
(
"3. root %x
\n
"
,
state
.
Root
())
// Add the amount to receivers account which should conclude this transaction
receiver
.
AddAmount
(
tx
.
Value
)
state
.
UpdateStateObject
(
receiver
)
fmt
.
Printf
(
"2. root %x
\n
"
,
state
.
Root
())
}
ethutil
.
Config
.
Log
.
Infof
(
"[TXPL] Processed Tx %x
\n
"
,
tx
.
Hash
())
return
}
func
(
sm
*
StateManager
)
ApplyTransaction
(
coinbase
[]
byte
,
state
*
State
,
block
*
Block
,
tx
*
Transaction
)
(
totalGasUsed
*
big
.
Int
,
err
error
)
{
/*
Applies transactions to the given state and creates new
state objects where needed.
If said objects needs to be created
run the initialization script provided by the transaction and
assume there's a return value. The return value will be set to
the script section of the state object.
*/
var
(
addTotalGas
=
func
(
gas
*
big
.
Int
)
{
totalGasUsed
.
Add
(
totalGasUsed
,
gas
)
}
gas
=
new
(
big
.
Int
)
script
[]
byte
)
totalGasUsed
=
big
.
NewInt
(
0
)
snapshot
:=
state
.
Snapshot
()
ca
:=
state
.
GetAccount
(
coinbase
)
// Apply the transaction to the current state
gas
,
err
=
sm
.
ProcessTransaction
(
tx
,
ca
,
state
,
false
)
addTotalGas
(
gas
)
fmt
.
Println
(
"gas used by tx"
,
gas
)
if
tx
.
CreatesContract
()
{
if
err
==
nil
{
// Create a new state object and the transaction
// as it's data provider.
contract
:=
sm
.
MakeStateObject
(
state
,
tx
)
if
contract
!=
nil
{
fmt
.
Println
(
Disassemble
(
contract
.
Init
()))
// Evaluate the initialization script
// and use the return value as the
// script section for the state object.
script
,
gas
,
err
=
sm
.
EvalScript
(
state
,
contract
.
Init
(),
contract
,
tx
,
block
)
fmt
.
Println
(
"gas used by eval"
,
gas
)
addTotalGas
(
gas
)
fmt
.
Println
(
"total ="
,
totalGasUsed
)
fmt
.
Println
(
"script len ="
,
len
(
script
))
if
err
!=
nil
{
err
=
fmt
.
Errorf
(
"[STATE] Error during init script run %v"
,
err
)
return
}
contract
.
script
=
script
state
.
UpdateStateObject
(
contract
)
}
else
{
err
=
fmt
.
Errorf
(
"[STATE] Unable to create contract"
)
}
}
else
{
err
=
fmt
.
Errorf
(
"[STATE] contract creation tx: %v for sender %x"
,
err
,
tx
.
Sender
())
}
}
else
{
// Find the state object at the "recipient" address. If
// there's an object attempt to run the script.
stateObject
:=
state
.
GetStateObject
(
tx
.
Recipient
)
if
err
==
nil
&&
stateObject
!=
nil
&&
len
(
stateObject
.
Script
())
>
0
{
_
,
gas
,
err
=
sm
.
EvalScript
(
state
,
stateObject
.
Script
(),
stateObject
,
tx
,
block
)
addTotalGas
(
gas
)
}
}
parent
:=
sm
.
bc
.
GetBlock
(
block
.
PrevHash
)
total
:=
new
(
big
.
Int
)
.
Add
(
block
.
GasUsed
,
totalGasUsed
)
limit
:=
block
.
CalcGasLimit
(
parent
)
if
total
.
Cmp
(
limit
)
>
0
{
state
.
Revert
(
snapshot
)
err
=
GasLimitError
(
total
,
limit
)
}
return
}
// Apply transactions uses the transaction passed to it and applies them onto
// the current processing state.
func
(
sm
*
StateManager
)
ApplyTransactions
(
coinbase
[]
byte
,
state
*
State
,
block
*
Block
,
txs
[]
*
Transaction
)
([]
*
Receipt
,
[]
*
Transaction
)
{
// Process each transaction/contract
var
receipts
[]
*
Receipt
var
validTxs
[]
*
Transaction
var
ignoredTxs
[]
*
Transaction
// Transactions which go over the gasLimit
totalUsedGas
:=
big
.
NewInt
(
0
)
for
_
,
tx
:=
range
txs
{
usedGas
,
err
:=
sm
.
ApplyTransaction
(
coinbase
,
state
,
block
,
tx
)
if
err
!=
nil
{
if
IsNonceErr
(
err
)
{
continue
}
if
IsGasLimitErr
(
err
)
{
ignoredTxs
=
append
(
ignoredTxs
,
tx
)
// We need to figure out if we want to do something with thse txes
ethutil
.
Config
.
Log
.
Debugln
(
"Gastlimit:"
,
err
)
continue
}
ethutil
.
Config
.
Log
.
Infoln
(
err
)
}
accumelative
:=
new
(
big
.
Int
)
.
Set
(
totalUsedGas
.
Add
(
totalUsedGas
,
usedGas
))
receipt
:=
&
Receipt
{
tx
,
ethutil
.
CopyBytes
(
state
.
Root
()
.
([]
byte
)),
accumelative
}
receipts
=
append
(
receipts
,
receipt
)
validTxs
=
append
(
validTxs
,
tx
)
}
fmt
.
Println
(
"################# MADE
\n
"
,
receipts
,
"
\n
############################"
)
// Update the total gas used for the block (to be mined)
block
.
GasUsed
=
totalUsedGas
return
receipts
,
validTxs
}
ethchain/error.go
View file @
5a0e7517
...
...
@@ -2,6 +2,7 @@ package ethchain
import
(
"fmt"
"math/big"
)
// Parent error. In case a parent is unknown this error will be thrown
...
...
@@ -43,6 +44,23 @@ func IsValidationErr(err error) bool {
return
ok
}
type
GasLimitErr
struct
{
Message
string
Is
,
Max
*
big
.
Int
}
func
IsGasLimitErr
(
err
error
)
bool
{
_
,
ok
:=
err
.
(
*
GasLimitErr
)
return
ok
}
func
(
err
*
GasLimitErr
)
Error
()
string
{
return
err
.
Message
}
func
GasLimitError
(
is
,
max
*
big
.
Int
)
*
GasLimitErr
{
return
&
GasLimitErr
{
Message
:
fmt
.
Sprintf
(
"GasLimit error. Max %s, transaction would take it to %s"
,
max
,
is
),
Is
:
is
,
Max
:
max
}
}
type
NonceErr
struct
{
Message
string
Is
,
Exp
uint64
...
...
@@ -61,3 +79,20 @@ func IsNonceErr(err error) bool {
return
ok
}
type
OutOfGasErr
struct
{
Message
string
}
func
OutOfGasError
()
*
OutOfGasErr
{
return
&
OutOfGasErr
{
Message
:
"Out of gas"
}
}
func
(
self
*
OutOfGasErr
)
Error
()
string
{
return
self
.
Message
}
func
IsOutOfGasErr
(
err
error
)
bool
{
_
,
ok
:=
err
.
(
*
OutOfGasErr
)
return
ok
}
ethchain/fees.go
View file @
5a0e7517
...
...
@@ -4,30 +4,6 @@ import (
"math/big"
)
var
TxFeeRat
*
big
.
Int
=
big
.
NewInt
(
100000000000000
)
var
TxFee
*
big
.
Int
=
big
.
NewInt
(
100
)
var
StepFee
*
big
.
Int
=
big
.
NewInt
(
1
)
var
StoreFee
*
big
.
Int
=
big
.
NewInt
(
5
)
var
DataFee
*
big
.
Int
=
big
.
NewInt
(
20
)
var
ExtroFee
*
big
.
Int
=
big
.
NewInt
(
40
)
var
CryptoFee
*
big
.
Int
=
big
.
NewInt
(
20
)
var
ContractFee
*
big
.
Int
=
big
.
NewInt
(
100
)
var
BlockReward
*
big
.
Int
=
big
.
NewInt
(
1.5e+18
)
var
UncleReward
*
big
.
Int
=
big
.
NewInt
(
1.125e+18
)
var
UncleInclusionReward
*
big
.
Int
=
big
.
NewInt
(
1.875e+17
)
var
Period1Reward
*
big
.
Int
=
new
(
big
.
Int
)
var
Period2Reward
*
big
.
Int
=
new
(
big
.
Int
)
var
Period3Reward
*
big
.
Int
=
new
(
big
.
Int
)
var
Period4Reward
*
big
.
Int
=
new
(
big
.
Int
)
func
InitFees
()
{
StepFee
.
Mul
(
StepFee
,
TxFeeRat
)
StoreFee
.
Mul
(
StoreFee
,
TxFeeRat
)
DataFee
.
Mul
(
DataFee
,
TxFeeRat
)
ExtroFee
.
Mul
(
ExtroFee
,
TxFeeRat
)
CryptoFee
.
Mul
(
CryptoFee
,
TxFeeRat
)
ContractFee
.
Mul
(
ContractFee
,
TxFeeRat
)
}
ethchain/stack.go
View file @
5a0e7517
...
...
@@ -111,6 +111,12 @@ func (m *Memory) Set(offset, size int64, value []byte) {
copy
(
m
.
store
[
offset
:
offset
+
size
],
value
)
}
func
(
m
*
Memory
)
Resize
(
size
uint64
)
{
if
uint64
(
m
.
Len
())
<
size
{
m
.
store
=
append
(
m
.
store
,
make
([]
byte
,
size
-
uint64
(
m
.
Len
()))
...
)
}
}
func
(
m
*
Memory
)
Get
(
offset
,
size
int64
)
[]
byte
{
return
m
.
store
[
offset
:
offset
+
size
]
}
...
...
ethchain/state.go
View file @
5a0e7517
...
...
@@ -16,12 +16,14 @@ type State struct {
// Nested states
states
map
[
string
]
*
State
stateObjects
map
[
string
]
*
StateObject
manifest
*
Manifest
}
// Create a new state from a given trie
func
NewState
(
trie
*
ethutil
.
Trie
)
*
State
{
return
&
State
{
trie
:
trie
,
states
:
make
(
map
[
string
]
*
State
),
manifest
:
NewManifest
()}
return
&
State
{
trie
:
trie
,
states
:
make
(
map
[
string
]
*
State
),
stateObjects
:
make
(
map
[
string
]
*
StateObject
),
manifest
:
NewManifest
()}
}
// Resets the trie and all siblings
...
...
@@ -29,16 +31,24 @@ func (s *State) Reset() {
s
.
trie
.
Undo
()
// Reset all nested states
for
_
,
state
:=
range
s
.
states
{
state
.
Reset
()
for
_
,
stateObject
:=
range
s
.
stateObjects
{
if
stateObject
.
state
==
nil
{
continue
}
stateObject
.
state
.
Reset
()
}
}
// Syncs the trie and all siblings
func
(
s
*
State
)
Sync
()
{
// Sync all nested states
for
_
,
state
:=
range
s
.
states
{
state
.
Sync
()
for
_
,
stateObject
:=
range
s
.
stateObjects
{
if
stateObject
.
state
==
nil
{
continue
}
stateObject
.
state
.
Sync
()
}
s
.
trie
.
Sync
()
...
...
@@ -54,62 +64,66 @@ func (s *State) EachStorage(cb ethutil.EachCallback) {
it
.
Each
(
cb
)
}
func
(
s
*
State
)
GetStateObject
(
addr
[]
byte
)
*
StateObject
{
data
:=
s
.
trie
.
Get
(
string
(
addr
))
if
data
==
""
{
return
nil
func
(
self
*
State
)
UpdateStateObject
(
stateObject
*
StateObject
)
{
addr
:=
stateObject
.
Address
()
if
self
.
stateObjects
[
string
(
addr
)]
==
nil
{
self
.
stateObjects
[
string
(
addr
)]
=
stateObject
}
stateObject
:=
NewStateObjectFromBytes
(
addr
,
[]
byte
(
data
))
ethutil
.
Config
.
Db
.
Put
(
ethutil
.
Sha3Bin
(
stateObject
.
Script
()),
stateObject
.
Script
(
))
// Check if there's a cached state for this contract
cachedStateObject
:=
s
.
states
[
string
(
addr
)]
if
cachedStateObject
!=
nil
{
//fmt.Printf("get cached #%d %x addr: %x\n", cachedStateObject.trie.Cache().Len(), cachedStateObject.Root(), addr[0:4])
stateObject
.
state
=
cachedStateObject
}
self
.
trie
.
Update
(
string
(
addr
),
string
(
stateObject
.
RlpEncode
()))
return
stateObject
self
.
manifest
.
AddObjectChange
(
stateObject
)
}
// Updates any given state object
func
(
s
*
State
)
UpdateStateObject
(
object
*
StateObject
)
{
addr
:=
object
.
Address
()
if
object
.
state
!=
nil
&&
s
.
states
[
string
(
addr
)]
==
nil
{
s
.
states
[
string
(
addr
)]
=
object
.
state
//fmt.Printf("update cached #%d %x addr: %x\n", object.state.trie.Cache().Len(), object.state.Root(), addr[0:4])
func
(
self
*
State
)
GetStateObject
(
addr
[]
byte
)
*
StateObject
{
stateObject
:=
self
.
stateObjects
[
string
(
addr
)]
if
stateObject
!=
nil
{
return
stateObject
}
ethutil
.
Config
.
Db
.
Put
(
ethutil
.
Sha3Bin
(
object
.
Script
()),
object
.
Script
())
data
:=
self
.
trie
.
Get
(
string
(
addr
))
if
len
(
data
)
==
0
{
return
nil
}
s
.
trie
.
Update
(
string
(
addr
),
string
(
object
.
RlpEncode
()))
stateObject
=
NewStateObjectFromBytes
(
addr
,
[]
byte
(
data
))
self
.
stateObjects
[
string
(
addr
)]
=
stateObject
s
.
manifest
.
AddObjectChange
(
object
)
return
stateObject
}
func
(
s
*
State
)
GetAccount
(
addr
[]
byte
)
(
account
*
StateObject
)
{
data
:=
s
.
trie
.
Get
(
string
(
addr
))
if
data
==
""
{
account
=
NewAccount
(
addr
,
big
.
NewInt
(
0
))
}
else
{
account
=
NewStateObjectFromBytes
(
addr
,
[]
byte
(
data
))
func
(
self
*
State
)
GetOrNewStateObject
(
addr
[]
byte
)
*
StateObject
{
stateObject
:=
self
.
GetStateObject
(
addr
)
if
stateObject
==
nil
{
stateObject
=
NewStateObject
(
addr
)
self
.
stateObjects
[
string
(
addr
)]
=
stateObject
}
return
return
stateObject
}
func
(
self
*
State
)
GetAccount
(
addr
[]
byte
)
*
StateObject
{
return
self
.
GetOrNewStateObject
(
addr
)
}
func
(
s
*
State
)
Cmp
(
other
*
State
)
bool
{
return
s
.
trie
.
Cmp
(
other
.
trie
)
}
func
(
s
*
State
)
Copy
()
*
State
{
state
:=
NewState
(
s
.
trie
.
Copy
())
for
k
,
subState
:=
range
s
.
states
{
state
.
states
[
k
]
=
subState
.
Copy
()
func
(
self
*
State
)
Copy
()
*
State
{
if
self
.
trie
!=
nil
{
state
:=
NewState
(
self
.
trie
.
Copy
())
for
k
,
stateObject
:=
range
self
.
stateObjects
{
state
.
stateObjects
[
k
]
=
stateObject
.
Copy
()
}
return
state
}
return
nil
}
func
(
s
*
State
)
Snapshot
()
*
State
{
...
...
@@ -165,3 +179,84 @@ func (m *Manifest) AddStorageChange(stateObject *StateObject, storageAddr []byte
m
.
storageChanges
[
string
(
stateObject
.
Address
())][
string
(
storageAddr
)]
=
storage
}
/*
// Resets the trie and all siblings
func (s *State) Reset() {
s.trie.Undo()
// Reset all nested states
for _, state := range s.states {
state.Reset()
}
}
// Syncs the trie and all siblings
func (s *State) Sync() {
// Sync all nested states
for _, state := range s.states {
state.Sync()
}
s.trie.Sync()
}
func (s *State) GetStateObject(addr []byte) *StateObject {
data := s.trie.Get(string(addr))
if data == "" {
return nil
}
stateObject := NewStateObjectFromBytes(addr, []byte(data))
// Check if there's a cached state for this contract
cachedStateObject := s.states[string(addr)]
if cachedStateObject != nil {
//fmt.Printf("get cached #%d %x addr: %x\n", cachedStateObject.trie.Cache().Len(), cachedStateObject.Root(), addr[0:4])
stateObject.state = cachedStateObject
}
return stateObject
}
// Updates any given state object
func (s *State) UpdateStateObject(object *StateObject) {
addr := object.Address()
if object.state != nil && s.states[string(addr)] == nil {
s.states[string(addr)] = object.state
}
ethutil.Config.Db.Put(ethutil.Sha3Bin(object.Script()), object.Script())
s.trie.Update(string(addr), string(object.RlpEncode()))
s.manifest.AddObjectChange(object)
}
func (s *State) GetAccount(addr []byte) (account *StateObject) {
data := s.trie.Get(string(addr))
if data == "" {
account = NewAccount(addr, big.NewInt(0))
} else {
account = NewStateObjectFromBytes(addr, []byte(data))
}
// Check if there's a cached state for this contract
cachedStateObject := s.states[string(addr)]
if cachedStateObject != nil {
account.state = cachedStateObject
}
return
}
func (s *State) Copy() *State {
state := NewState(s.trie.Copy())
for k, subState := range s.states {
state.states[k] = subState.Copy()
}
return state
}
*/
ethchain/state_manager.go
View file @
5a0e7517
...
...
@@ -97,100 +97,49 @@ func (sm *StateManager) BlockChain() *BlockChain {
return
sm
.
bc
}
func
(
sm
*
StateManager
)
MakeStateObject
(
state
*
State
,
tx
*
Transaction
)
*
StateObject
{
contract
:=
MakeContract
(
tx
,
state
)
if
contract
!=
nil
{
state
.
states
[
string
(
tx
.
CreationAddress
())]
=
contract
.
state
return
contract
}
return
nil
}
func
(
self
*
StateManager
)
ProcessTransactions
(
coinbase
*
StateObject
,
state
*
State
,
block
,
parent
*
Block
,
txs
Transactions
)
(
Receipts
,
Transactions
,
Transactions
,
error
)
{
var
(
receipts
Receipts
handled
,
unhandled
Transactions
totalUsedGas
=
big
.
NewInt
(
0
)
err
error
)
// Apply transactions uses the transaction passed to it and applies them onto
// the current processing state.
func
(
sm
*
StateManager
)
ApplyTransactions
(
state
*
State
,
block
*
Block
,
txs
[]
*
Transaction
)
([]
*
Receipt
,
[]
*
Transaction
)
{
// Process each transaction/contract
var
receipts
[]
*
Receipt
var
validTxs
[]
*
Transaction
totalUsedGas
:=
big
.
NewInt
(
0
)
for
_
,
tx
:=
range
txs
{
usedGas
,
err
:=
sm
.
ApplyTransaction
(
state
,
block
,
tx
)
done
:
for
i
,
tx
:=
range
txs
{
txGas
:=
new
(
big
.
Int
)
.
Set
(
tx
.
Gas
)
st
:=
NewStateTransition
(
coinbase
,
tx
,
state
,
block
)
err
=
st
.
TransitionState
()
if
err
!=
nil
{
if
IsNonceErr
(
err
)
{
switch
{
case
IsNonceErr
(
err
)
:
err
=
nil
// ignore error
continue
}
case
IsGasLimitErr
(
err
)
:
unhandled
=
txs
[
i
:
]
break
done
default
:
ethutil
.
Config
.
Log
.
Infoln
(
err
)
}
}
accumelative
:=
new
(
big
.
Int
)
.
Set
(
totalUsedGas
.
Add
(
totalUsedGas
,
usedGas
))
// Notify all subscribers
self
.
Ethereum
.
Reactor
()
.
Post
(
"newTx:post"
,
tx
)
txGas
.
Sub
(
txGas
,
st
.
gas
)
accumelative
:=
new
(
big
.
Int
)
.
Set
(
totalUsedGas
.
Add
(
totalUsedGas
,
txGas
))
receipt
:=
&
Receipt
{
tx
,
ethutil
.
CopyBytes
(
state
.
Root
()
.
([]
byte
)),
accumelative
}
receipts
=
append
(
receipts
,
receipt
)
validTxs
=
append
(
validTxs
,
tx
)
handled
=
append
(
handled
,
tx
)
}
return
receipts
,
validTxs
}
func
(
sm
*
StateManager
)
ApplyTransaction
(
state
*
State
,
block
*
Block
,
tx
*
Transaction
)
(
totalGasUsed
*
big
.
Int
,
err
error
)
{
/*
Applies transactions to the given state and creates new
state objects where needed.
fmt
.
Println
(
"################# MADE
\n
"
,
receipts
,
"
\n
############################"
)
If said objects needs to be created
run the initialization script provided by the transaction and
assume there's a return value. The return value will be set to
the script section of the state object.
*/
var
(
addTotalGas
=
func
(
gas
*
big
.
Int
)
{
totalGasUsed
.
Add
(
totalGasUsed
,
gas
)
}
gas
=
new
(
big
.
Int
)
script
[]
byte
)
totalGasUsed
=
big
.
NewInt
(
0
)
// Apply the transaction to the current state
gas
,
err
=
sm
.
Ethereum
.
TxPool
()
.
ProcessTransaction
(
tx
,
state
,
false
)
addTotalGas
(
gas
)
if
tx
.
CreatesContract
()
{
if
err
==
nil
{
// Create a new state object and the transaction
// as it's data provider.
contract
:=
sm
.
MakeStateObject
(
state
,
tx
)
if
contract
!=
nil
{
// Evaluate the initialization script
// and use the return value as the
// script section for the state object.
script
,
gas
,
err
=
sm
.
EvalScript
(
state
,
contract
.
Init
(),
contract
,
tx
,
block
)
addTotalGas
(
gas
)
parent
.
GasUsed
=
totalUsedGas
if
err
!=
nil
{
err
=
fmt
.
Errorf
(
"[STATE] Error during init script run %v"
,
err
)
return
}
contract
.
script
=
script
state
.
UpdateStateObject
(
contract
)
}
else
{
err
=
fmt
.
Errorf
(
"[STATE] Unable to create contract"
)
}
}
else
{
err
=
fmt
.
Errorf
(
"[STATE] contract creation tx: %v for sender %x"
,
err
,
tx
.
Sender
())
}
}
else
{
// Find the state object at the "recipient" address. If
// there's an object attempt to run the script.
stateObject
:=
state
.
GetStateObject
(
tx
.
Recipient
)
if
err
==
nil
&&
stateObject
!=
nil
&&
len
(
stateObject
.
Script
())
>
0
{
_
,
gas
,
err
=
sm
.
EvalScript
(
state
,
stateObject
.
Script
(),
stateObject
,
tx
,
block
)
addTotalGas
(
gas
)
}
}
return
return
receipts
,
handled
,
unhandled
,
err
}
func
(
sm
*
StateManager
)
Process
(
block
*
Block
,
dontReact
bool
)
error
{
...
...
@@ -212,7 +161,6 @@ func (sm *StateManager) ProcessBlock(state *State, parent, block *Block, dontRea
hash
:=
block
.
Hash
()
if
sm
.
bc
.
HasBlock
(
hash
)
{
//fmt.Println("[STATE] We already have this block, ignoring")
return
nil
}
...
...
@@ -227,9 +175,14 @@ func (sm *StateManager) ProcessBlock(state *State, parent, block *Block, dontRea
if
!
sm
.
bc
.
HasBlock
(
block
.
PrevHash
)
&&
sm
.
bc
.
CurrentBlock
!=
nil
{
return
ParentError
(
block
.
PrevHash
)
}
fmt
.
Println
(
block
.
Receipts
())
coinbase
:=
state
.
GetOrNewStateObject
(
block
.
Coinbase
)
coinbase
.
SetGasPool
(
block
.
CalcGasLimit
(
parent
))
// Process the transactions on to current block
sm
.
ApplyTransactions
(
state
,
parent
,
block
.
Transactions
())
//sm.ApplyTransactions(block.Coinbase, state, parent, block.Transactions())
sm
.
ProcessTransactions
(
coinbase
,
state
,
block
,
parent
,
block
.
Transactions
())
// Block validation
if
err
:=
sm
.
ValidateBlock
(
block
);
err
!=
nil
{
...
...
@@ -244,7 +197,6 @@ func (sm *StateManager) ProcessBlock(state *State, parent, block *Block, dontRea
return
err
}
//if !sm.compState.Cmp(state) {
if
!
block
.
State
()
.
Cmp
(
state
)
{
return
fmt
.
Errorf
(
"Invalid merkle root.
\n
rec: %x
\n
is: %x"
,
block
.
State
()
.
trie
.
Root
,
state
.
trie
.
Root
)
}
...
...
@@ -337,13 +289,6 @@ func CalculateBlockReward(block *Block, uncleLength int) *big.Int {
base
.
Add
(
base
,
UncleInclusionReward
)
}
lastCumulGasUsed
:=
big
.
NewInt
(
0
)
for
_
,
r
:=
range
block
.
Receipts
()
{
usedGas
:=
new
(
big
.
Int
)
.
Sub
(
r
.
CumulativeGasUsed
,
lastCumulGasUsed
)
usedGas
.
Add
(
usedGas
,
r
.
Tx
.
GasPrice
)
base
.
Add
(
base
,
usedGas
)
}
return
base
.
Add
(
base
,
BlockReward
)
}
...
...
@@ -375,35 +320,6 @@ func (sm *StateManager) Stop() {
sm
.
bc
.
Stop
()
}
func
(
sm
*
StateManager
)
EvalScript
(
state
*
State
,
script
[]
byte
,
object
*
StateObject
,
tx
*
Transaction
,
block
*
Block
)
(
ret
[]
byte
,
gas
*
big
.
Int
,
err
error
)
{
account
:=
state
.
GetAccount
(
tx
.
Sender
())
err
=
account
.
ConvertGas
(
tx
.
Gas
,
tx
.
GasPrice
)
if
err
!=
nil
{
ethutil
.
Config
.
Log
.
Debugln
(
err
)
return
}
closure
:=
NewClosure
(
account
,
object
,
script
,
state
,
tx
.
Gas
,
tx
.
GasPrice
)
vm
:=
NewVm
(
state
,
sm
,
RuntimeVars
{
Origin
:
account
.
Address
(),
BlockNumber
:
block
.
BlockInfo
()
.
Number
,
PrevHash
:
block
.
PrevHash
,
Coinbase
:
block
.
Coinbase
,
Time
:
block
.
Time
,
Diff
:
block
.
Difficulty
,
Value
:
tx
.
Value
,
//Price: tx.GasPrice,
})
ret
,
gas
,
err
=
closure
.
Call
(
vm
,
tx
.
Data
,
nil
)
// Update the account (refunds)
state
.
UpdateStateObject
(
account
)
state
.
UpdateStateObject
(
object
)
return
}
func
(
sm
*
StateManager
)
notifyChanges
(
state
*
State
)
{
for
addr
,
stateObject
:=
range
state
.
manifest
.
objectChanges
{
sm
.
Ethereum
.
Reactor
()
.
Post
(
"object:"
+
addr
,
stateObject
)
...
...
ethchain/state_object.go
View file @
5a0e7517
...
...
@@ -17,6 +17,11 @@ type StateObject struct {
state
*
State
script
[]
byte
initScript
[]
byte
// Total gas pool is the total amount of gas currently
// left if this object is the coinbase. Gas is directly
// purchased of the coinbase.
gasPool
*
big
.
Int
}
// Converts an transaction in to a state object
...
...
@@ -38,6 +43,10 @@ func MakeContract(tx *Transaction, state *State) *StateObject {
return
nil
}
func
NewStateObject
(
addr
[]
byte
)
*
StateObject
{
return
&
StateObject
{
address
:
addr
,
Amount
:
new
(
big
.
Int
)}
}
func
NewContract
(
address
[]
byte
,
Amount
*
big
.
Int
,
root
[]
byte
)
*
StateObject
{
contract
:=
&
StateObject
{
address
:
address
,
Amount
:
Amount
,
Nonce
:
0
}
contract
.
state
=
NewState
(
ethutil
.
NewTrie
(
ethutil
.
Config
.
Db
,
string
(
root
)))
...
...
@@ -77,7 +86,7 @@ func (c *StateObject) SetAddr(addr []byte, value interface{}) {
func
(
c
*
StateObject
)
SetStorage
(
num
*
big
.
Int
,
val
*
ethutil
.
Value
)
{
addr
:=
ethutil
.
BigToBytes
(
num
,
256
)
//fmt.Print
ln("storing", val.BigInt(), "@", num
)
//fmt.Print
f("sstore %x => %v\n", addr, val
)
c
.
SetAddr
(
addr
,
val
)
}
...
...
@@ -102,16 +111,22 @@ func (c *StateObject) GetInstr(pc *big.Int) *ethutil.Value {
// Return the gas back to the origin. Used by the Virtual machine or Closures
func
(
c
*
StateObject
)
ReturnGas
(
gas
,
price
*
big
.
Int
,
state
*
State
)
{
/*
remainder := new(big.Int).Mul(gas, price)
c.AddAmount(remainder)
*/
}
func
(
c
*
StateObject
)
AddAmount
(
amount
*
big
.
Int
)
{
c
.
SetAmount
(
new
(
big
.
Int
)
.
Add
(
c
.
Amount
,
amount
))
ethutil
.
Config
.
Log
.
Printf
(
ethutil
.
LogLevelSystem
,
"%x: #%d %v (+ %v)
\n
"
,
c
.
Address
(),
c
.
Nonce
,
c
.
Amount
,
amount
)
}
func
(
c
*
StateObject
)
SubAmount
(
amount
*
big
.
Int
)
{
c
.
SetAmount
(
new
(
big
.
Int
)
.
Sub
(
c
.
Amount
,
amount
))
ethutil
.
Config
.
Log
.
Printf
(
ethutil
.
LogLevelSystem
,
"%x: #%d %v (- %v)
\n
"
,
c
.
Address
(),
c
.
Nonce
,
c
.
Amount
,
amount
)
}
func
(
c
*
StateObject
)
SetAmount
(
amount
*
big
.
Int
)
{
...
...
@@ -129,6 +144,53 @@ func (c *StateObject) ConvertGas(gas, price *big.Int) error {
return
nil
}
func
(
self
*
StateObject
)
SetGasPool
(
gasLimit
*
big
.
Int
)
{
self
.
gasPool
=
new
(
big
.
Int
)
.
Set
(
gasLimit
)
ethutil
.
Config
.
Log
.
Printf
(
ethutil
.
LogLevelSystem
,
"%x: fuel (+ %v)"
,
self
.
Address
(),
self
.
gasPool
)
}
func
(
self
*
StateObject
)
BuyGas
(
gas
,
price
*
big
.
Int
)
error
{
if
self
.
gasPool
.
Cmp
(
gas
)
<
0
{
return
GasLimitError
(
self
.
gasPool
,
gas
)
}
rGas
:=
new
(
big
.
Int
)
.
Set
(
gas
)
rGas
.
Mul
(
rGas
,
price
)
self
.
AddAmount
(
rGas
)
return
nil
}
func
(
self
*
StateObject
)
RefundGas
(
gas
,
price
*
big
.
Int
)
{
self
.
gasPool
.
Add
(
self
.
gasPool
,
gas
)
rGas
:=
new
(
big
.
Int
)
.
Set
(
gas
)
rGas
.
Mul
(
rGas
,
price
)
self
.
Amount
.
Sub
(
self
.
Amount
,
rGas
)
}
func
(
self
*
StateObject
)
Copy
()
*
StateObject
{
stCopy
:=
&
StateObject
{}
stCopy
.
address
=
make
([]
byte
,
len
(
self
.
address
))
copy
(
stCopy
.
address
,
self
.
address
)
stCopy
.
Amount
=
new
(
big
.
Int
)
.
Set
(
self
.
Amount
)
stCopy
.
ScriptHash
=
make
([]
byte
,
len
(
self
.
ScriptHash
))
copy
(
stCopy
.
ScriptHash
,
self
.
ScriptHash
)
stCopy
.
Nonce
=
self
.
Nonce
if
self
.
state
!=
nil
{
stCopy
.
state
=
self
.
state
.
Copy
()
}
stCopy
.
script
=
make
([]
byte
,
len
(
self
.
script
))
copy
(
stCopy
.
script
,
self
.
script
)
stCopy
.
initScript
=
make
([]
byte
,
len
(
self
.
initScript
))
copy
(
stCopy
.
initScript
,
self
.
initScript
)
return
stCopy
}
// Returns the address of the contract/account
func
(
c
*
StateObject
)
Address
()
[]
byte
{
return
c
.
address
...
...
@@ -153,14 +215,14 @@ func (c *StateObject) RlpEncode() []byte {
root
=
""
}
return
ethutil
.
Encode
([]
interface
{}{
c
.
Amount
,
c
.
Nonce
,
root
,
ethutil
.
Sha3Bin
(
c
.
script
)})
return
ethutil
.
Encode
([]
interface
{}{
c
.
Nonce
,
c
.
Amount
,
root
,
ethutil
.
Sha3Bin
(
c
.
script
)})
}
func
(
c
*
StateObject
)
RlpDecode
(
data
[]
byte
)
{
decoder
:=
ethutil
.
NewValueFromBytes
(
data
)
c
.
Amount
=
decoder
.
Get
(
0
)
.
BigI
nt
()
c
.
Nonce
=
decoder
.
Get
(
1
)
.
Ui
nt
()
c
.
Nonce
=
decoder
.
Get
(
0
)
.
Ui
nt
()
c
.
Amount
=
decoder
.
Get
(
1
)
.
BigI
nt
()
c
.
state
=
NewState
(
ethutil
.
NewTrie
(
ethutil
.
Config
.
Db
,
decoder
.
Get
(
2
)
.
Interface
()))
c
.
ScriptHash
=
decoder
.
Get
(
3
)
.
Bytes
()
...
...
ethchain/state_transition.go
0 → 100644
View file @
5a0e7517
package
ethchain
import
(
"fmt"
"github.com/ethereum/eth-go/ethutil"
"math/big"
)
/*
* The State transitioning model
*
* A state transition is a change made when a transaction is applied to the current world state
* The state transitioning model does all all the necessary work to work out a valid new state root.
* 1) Nonce handling
* 2) Pre pay / buy gas of the coinbase (miner)
* 3) Create a new state object if the recipient is \0*32
* 4) Value transfer
* == If contract creation ==
* 4a) Attempt to run transaction data
* 4b) If valid, use result as code for the new state object
* == end ==
* 5) Run Script section
* 6) Derive new state root
*/
type
StateTransition
struct
{
coinbase
[]
byte
tx
*
Transaction
gas
*
big
.
Int
state
*
State
block
*
Block
cb
,
rec
,
sen
*
StateObject
}
func
NewStateTransition
(
coinbase
*
StateObject
,
tx
*
Transaction
,
state
*
State
,
block
*
Block
)
*
StateTransition
{
return
&
StateTransition
{
coinbase
.
Address
(),
tx
,
new
(
big
.
Int
),
state
,
block
,
coinbase
,
nil
,
nil
}
}
func
(
self
*
StateTransition
)
Coinbase
()
*
StateObject
{
if
self
.
cb
!=
nil
{
return
self
.
cb
}
self
.
cb
=
self
.
state
.
GetAccount
(
self
.
coinbase
)
return
self
.
cb
}
func
(
self
*
StateTransition
)
Sender
()
*
StateObject
{
if
self
.
sen
!=
nil
{
return
self
.
sen
}
self
.
sen
=
self
.
state
.
GetAccount
(
self
.
tx
.
Sender
())
return
self
.
sen
}
func
(
self
*
StateTransition
)
Receiver
()
*
StateObject
{
if
self
.
tx
.
CreatesContract
()
{
return
nil
}
if
self
.
rec
!=
nil
{
return
self
.
rec
}
self
.
rec
=
self
.
state
.
GetAccount
(
self
.
tx
.
Recipient
)
return
self
.
rec
}
func
(
self
*
StateTransition
)
MakeStateObject
(
state
*
State
,
tx
*
Transaction
)
*
StateObject
{
contract
:=
MakeContract
(
tx
,
state
)
if
contract
!=
nil
{
state
.
states
[
string
(
tx
.
CreationAddress
())]
=
contract
.
state
return
contract
}
return
nil
}
func
(
self
*
StateTransition
)
UseGas
(
amount
*
big
.
Int
)
error
{
if
self
.
gas
.
Cmp
(
amount
)
<
0
{
return
OutOfGasError
()
}
self
.
gas
.
Sub
(
self
.
gas
,
amount
)
return
nil
}
func
(
self
*
StateTransition
)
AddGas
(
amount
*
big
.
Int
)
{
self
.
gas
.
Add
(
self
.
gas
,
amount
)
}
func
(
self
*
StateTransition
)
BuyGas
()
error
{
var
err
error
sender
:=
self
.
Sender
()
if
sender
.
Amount
.
Cmp
(
self
.
tx
.
GasValue
())
<
0
{
return
fmt
.
Errorf
(
"Insufficient funds to pre-pay gas. Req %v, has %v"
,
self
.
tx
.
GasValue
(),
self
.
tx
.
Value
)
}
coinbase
:=
self
.
Coinbase
()
err
=
coinbase
.
BuyGas
(
self
.
tx
.
Gas
,
self
.
tx
.
GasPrice
)
if
err
!=
nil
{
return
err
}
//self.state.UpdateStateObject(coinbase)
self
.
AddGas
(
self
.
tx
.
Gas
)
sender
.
SubAmount
(
self
.
tx
.
GasValue
())
return
nil
}
func
(
self
*
StateTransition
)
RefundGas
()
{
coinbase
,
sender
:=
self
.
Coinbase
(),
self
.
Sender
()
coinbase
.
RefundGas
(
self
.
gas
,
self
.
tx
.
GasPrice
)
// Return remaining gas
remaining
:=
new
(
big
.
Int
)
.
Mul
(
self
.
gas
,
self
.
tx
.
GasPrice
)
sender
.
AddAmount
(
remaining
)
}
func
(
self
*
StateTransition
)
TransitionState
()
(
err
error
)
{
//snapshot := st.state.Snapshot()
/*
defer func() {
if r := recover(); r != nil {
ethutil.Config.Log.Infoln(r)
err = fmt.Errorf("state transition err %v", r)
}
}()
*/
var
(
tx
=
self
.
tx
sender
=
self
.
Sender
()
receiver
*
StateObject
)
// Make sure this transaction's nonce is correct
if
sender
.
Nonce
!=
tx
.
Nonce
{
return
NonceError
(
tx
.
Nonce
,
sender
.
Nonce
)
}
// Pre-pay gas / Buy gas of the coinbase account
if
err
=
self
.
BuyGas
();
err
!=
nil
{
return
err
}
// XXX Transactions after this point are considered valid.
defer
func
()
{
self
.
RefundGas
()
if
sender
!=
nil
{
self
.
state
.
UpdateStateObject
(
sender
)
}
if
receiver
!=
nil
{
self
.
state
.
UpdateStateObject
(
receiver
)
}
self
.
state
.
UpdateStateObject
(
self
.
Coinbase
())
}()
// Increment the nonce for the next transaction
sender
.
Nonce
+=
1
// Get the receiver (TODO fix this, if coinbase is the receiver we need to save/retrieve)
receiver
=
self
.
Receiver
()
// Transaction gas
if
err
=
self
.
UseGas
(
GasTx
);
err
!=
nil
{
return
err
}
// Pay data gas
dataPrice
:=
big
.
NewInt
(
int64
(
len
(
tx
.
Data
)))
dataPrice
.
Mul
(
dataPrice
,
GasData
)
if
err
=
self
.
UseGas
(
dataPrice
);
err
!=
nil
{
return
err
}
// If the receiver is nil it's a contract (\0*32).
if
receiver
==
nil
{
// Create a new state object for the contract
receiver
=
self
.
MakeStateObject
(
self
.
state
,
tx
)
if
receiver
==
nil
{
return
fmt
.
Errorf
(
"ERR. Unable to create contract with transaction %v"
,
tx
)
}
}
// Transfer value from sender to receiver
if
err
=
self
.
transferValue
(
sender
,
receiver
);
err
!=
nil
{
return
err
}
// Process the init code and create 'valid' contract
if
tx
.
CreatesContract
()
{
// Evaluate the initialization script
// and use the return value as the
// script section for the state object.
//script, gas, err = sm.Eval(state, contract.Init(), contract, tx, block)
code
,
err
:=
self
.
Eval
(
receiver
.
Init
(),
receiver
)
if
err
!=
nil
{
return
fmt
.
Errorf
(
"Error during init script run %v"
,
err
)
}
receiver
.
script
=
code
}
else
{
if
len
(
receiver
.
Script
())
>
0
{
_
,
err
:=
self
.
Eval
(
receiver
.
Script
(),
receiver
)
if
err
!=
nil
{
return
fmt
.
Errorf
(
"Error during code execution %v"
,
err
)
}
}
}
return
nil
}
func
(
self
*
StateTransition
)
transferValue
(
sender
,
receiver
*
StateObject
)
error
{
if
sender
.
Amount
.
Cmp
(
self
.
tx
.
Value
)
<
0
{
return
fmt
.
Errorf
(
"Insufficient funds to transfer value. Req %v, has %v"
,
self
.
tx
.
Value
,
sender
.
Amount
)
}
if
self
.
tx
.
Value
.
Cmp
(
ethutil
.
Big0
)
>
0
{
// Subtract the amount from the senders account
sender
.
SubAmount
(
self
.
tx
.
Value
)
// Add the amount to receivers account which should conclude this transaction
receiver
.
AddAmount
(
self
.
tx
.
Value
)
ethutil
.
Config
.
Log
.
Debugf
(
"%x => %x (%v) %x
\n
"
,
sender
.
Address
()[
:
4
],
receiver
.
Address
()[
:
4
],
self
.
tx
.
Value
,
self
.
tx
.
Hash
())
}
return
nil
}
func
(
self
*
StateTransition
)
Eval
(
script
[]
byte
,
context
*
StateObject
)
(
ret
[]
byte
,
err
error
)
{
var
(
tx
=
self
.
tx
block
=
self
.
block
initiator
=
self
.
Sender
()
state
=
self
.
state
)
closure
:=
NewClosure
(
initiator
,
context
,
script
,
state
,
self
.
gas
,
tx
.
GasPrice
)
vm
:=
NewVm
(
state
,
nil
,
RuntimeVars
{
Origin
:
initiator
.
Address
(),
BlockNumber
:
block
.
BlockInfo
()
.
Number
,
PrevHash
:
block
.
PrevHash
,
Coinbase
:
block
.
Coinbase
,
Time
:
block
.
Time
,
Diff
:
block
.
Difficulty
,
Value
:
tx
.
Value
,
})
ret
,
_
,
err
=
closure
.
Call
(
vm
,
tx
.
Data
,
nil
)
return
}
ethchain/transaction.go
View file @
5a0e7517
package
ethchain
import
(
"bytes"
"fmt"
"github.com/ethereum/eth-go/ethutil"
"github.com/obscuren/secp256k1-go"
...
...
@@ -24,7 +25,7 @@ type Transaction struct {
}
func
NewContractCreationTx
(
value
,
gas
,
gasPrice
*
big
.
Int
,
script
[]
byte
)
*
Transaction
{
return
&
Transaction
{
Value
:
value
,
Gas
:
gas
,
GasPrice
:
gasPrice
,
Data
:
script
,
contractCreation
:
true
}
return
&
Transaction
{
Recipient
:
ContractAddr
,
Value
:
value
,
Gas
:
gas
,
GasPrice
:
gasPrice
,
Data
:
script
,
contractCreation
:
true
}
}
func
NewTransactionMessage
(
to
[]
byte
,
value
,
gas
,
gasPrice
*
big
.
Int
,
data
[]
byte
)
*
Transaction
{
...
...
@@ -45,15 +46,18 @@ func NewTransactionFromValue(val *ethutil.Value) *Transaction {
return
tx
}
func
(
self
*
Transaction
)
GasValue
()
*
big
.
Int
{
return
new
(
big
.
Int
)
.
Mul
(
self
.
Gas
,
self
.
GasPrice
)
}
func
(
self
*
Transaction
)
TotalValue
()
*
big
.
Int
{
v
:=
self
.
GasValue
()
return
v
.
Add
(
v
,
self
.
Value
)
}
func
(
tx
*
Transaction
)
Hash
()
[]
byte
{
data
:=
[]
interface
{}{
tx
.
Nonce
,
tx
.
GasPrice
,
tx
.
Gas
,
tx
.
Recipient
,
tx
.
Value
,
tx
.
Data
}
/*
if tx.contractCreation {
data = append(data, tx.Init)
}
*/
return
ethutil
.
Sha3Bin
(
ethutil
.
NewValue
(
data
)
.
Encode
())
}
...
...
@@ -144,7 +148,8 @@ func (tx *Transaction) RlpValueDecode(decoder *ethutil.Value) {
tx
.
v
=
byte
(
decoder
.
Get
(
6
)
.
Uint
())
tx
.
r
=
decoder
.
Get
(
7
)
.
Bytes
()
tx
.
s
=
decoder
.
Get
(
8
)
.
Bytes
()
if
len
(
tx
.
Recipient
)
==
0
{
if
bytes
.
Compare
(
tx
.
Recipient
,
ContractAddr
)
==
0
{
tx
.
contractCreation
=
true
}
}
...
...
@@ -183,6 +188,7 @@ type Receipt struct {
PostState
[]
byte
CumulativeGasUsed
*
big
.
Int
}
type
Receipts
[]
*
Receipt
func
NewRecieptFromValue
(
val
*
ethutil
.
Value
)
*
Receipt
{
r
:=
&
Receipt
{}
...
...
ethchain/transaction_pool.go
View file @
5a0e7517
...
...
@@ -22,6 +22,7 @@ type TxMsgTy byte
const
(
TxPre
=
iota
TxPost
minGasPrice
=
1000000
)
type
TxMsg
struct
{
...
...
@@ -89,9 +90,11 @@ func (pool *TxPool) addTransaction(tx *Transaction) {
pool
.
Ethereum
.
Broadcast
(
ethwire
.
MsgTxTy
,
[]
interface
{}{
tx
.
RlpData
()})
}
/*
// Process transaction validates the Tx and processes funds from the
// sender to the recipient.
func (pool *TxPool) ProcessTransaction(tx *Transaction, state *State, toContract bool) (gas *big.Int, err error) {
fmt.Printf("state root before update %x\n", state.Root())
defer func() {
if r := recover(); r != nil {
ethutil.Config.Log.Infoln(r)
...
...
@@ -101,6 +104,7 @@ func (pool *TxPool) ProcessTransaction(tx *Transaction, state *State, toContract
gas = new(big.Int)
addGas := func(g *big.Int) { gas.Add(gas, g) }
addGas(GasTx)
// Get the sender
sender := state.GetAccount(tx.Sender())
...
...
@@ -110,28 +114,37 @@ func (pool *TxPool) ProcessTransaction(tx *Transaction, state *State, toContract
return
}
sender.Nonce += 1
defer func() {
//state.UpdateStateObject(sender)
// Notify all subscribers
pool.Ethereum.Reactor().Post("newTx:post", tx)
}()
txTotalBytes := big.NewInt(int64(len(tx.Data)))
txTotalBytes.Div(txTotalBytes, ethutil.Big32)
addGas(new(big.Int).Mul(txTotalBytes, GasSStore))
rGas := new(big.Int).Set(gas)
rGas.Mul(gas, tx.GasPrice)
// Make sure there's enough in the sender's account. Having insufficient
// funds won't invalidate this transaction but simple ignores it.
//totAmount := new(big.Int).Add(tx.Value, new(big.Int).Mul(TxFee, TxFeeRat))
totAmount
:=
new
(
big
.
Int
)
.
Add
(
tx
.
Value
,
new
(
big
.
Int
)
.
Mul
(
tx
.
Gas
,
tx
.
GasPrice
))
totAmount := new(big.Int).Add(tx.Value, rGas)
if sender.Amount.Cmp(totAmount) < 0 {
err = fmt.Errorf("[TXPL] Insufficient amount in sender's (%x) account", tx.Sender())
return
}
state.UpdateStateObject(sender)
fmt.Printf("state root after sender update %x\n", state.Root())
// Get the receiver
receiver := state.GetAccount(tx.Recipient)
sender
.
Nonce
+=
1
// Send Tx to self
if bytes.Compare(tx.Recipient, tx.Sender()) == 0 {
addGas
(
GasTx
)
// Subtract the fee
sender
.
SubAmount
(
new
(
big
.
Int
)
.
Mul
(
GasTx
,
tx
.
GasPrice
)
)
sender.SubAmount(
rGas
)
} else {
// Subtract the amount from the senders account
sender.SubAmount(totAmount)
...
...
@@ -140,17 +153,14 @@ func (pool *TxPool) ProcessTransaction(tx *Transaction, state *State, toContract
receiver.AddAmount(tx.Value)
state.UpdateStateObject(receiver)
fmt.Printf("state root after receiver update %x\n", state.Root())
}
state
.
UpdateStateObject
(
sender
)
ethutil.Config.Log.Infof("[TXPL] Processed Tx %x\n", tx.Hash())
// Notify all subscribers
pool
.
Ethereum
.
Reactor
()
.
Post
(
"newTx:post"
,
tx
)
return
}
*/
func
(
pool
*
TxPool
)
ValidateTransaction
(
tx
*
Transaction
)
error
{
// Get the last block so we can retrieve the sender and receiver from
...
...
@@ -161,17 +171,27 @@ func (pool *TxPool) ValidateTransaction(tx *Transaction) error {
return
errors
.
New
(
"[TXPL] No last block on the block chain"
)
}
if
len
(
tx
.
Recipient
)
!=
20
{
return
fmt
.
Errorf
(
"[TXPL] Invalid recipient. len = %d"
,
len
(
tx
.
Recipient
))
}
// Get the sender
//sender := pool.Ethereum.StateManager().procState.GetAccount(tx.Sender())
sender
:=
pool
.
Ethereum
.
StateManager
()
.
CurrentState
()
.
GetAccount
(
tx
.
Sender
())
totAmount
:=
new
(
big
.
Int
)
.
Add
(
tx
.
Value
,
new
(
big
.
Int
)
.
Mul
(
TxFee
,
TxFeeRat
)
)
totAmount
:=
new
(
big
.
Int
)
.
Set
(
tx
.
Value
)
// Make sure there's enough in the sender's account. Having insufficient
// funds won't invalidate this transaction but simple ignores it.
if
sender
.
Amount
.
Cmp
(
totAmount
)
<
0
{
return
fmt
.
Errorf
(
"[TXPL] Insufficient amount in sender's (%x) account"
,
tx
.
Sender
())
}
if
tx
.
IsContract
()
{
if
tx
.
GasPrice
.
Cmp
(
big
.
NewInt
(
minGasPrice
))
<
0
{
return
fmt
.
Errorf
(
"[TXPL] Gasprice to low, %s given should be at least %d."
,
tx
.
GasPrice
,
minGasPrice
)
}
}
// Increment the nonce making each tx valid only once to prevent replay
// attacks
...
...
@@ -200,6 +220,8 @@ out:
// Call blocking version.
pool
.
addTransaction
(
tx
)
ethutil
.
Config
.
Log
.
Debugf
(
"(t) %x => %x (%v) %x
\n
"
,
tx
.
Sender
()[
:
4
],
tx
.
Recipient
[
:
4
],
tx
.
Value
,
tx
.
Hash
())
// Notify the subscribers
pool
.
Ethereum
.
Reactor
()
.
Post
(
"newTx:pre"
,
tx
)
}
...
...
ethchain/types.go
View file @
5a0e7517
package
ethchain
import
(
"fmt"
)
type
OpCode
int
// Op codes
...
...
@@ -17,8 +21,10 @@ const (
NEG
=
0x09
LT
=
0x0a
GT
=
0x0b
EQ
=
0x0c
NOT
=
0x0d
SLT
=
0x0c
SGT
=
0x0d
EQ
=
0x0e
NOT
=
0x0f
// 0x10 range - bit ops
AND
=
0x10
...
...
@@ -37,7 +43,10 @@ const (
CALLVALUE
=
0x34
CALLDATALOAD
=
0x35
CALLDATASIZE
=
0x36
GASPRICE
=
0x37
CALLDATACOPY
=
0x37
CODESIZE
=
0x38
CODECOPY
=
0x39
GASPRICE
=
0x3a
// 0x40 range - block operations
PREVHASH
=
0x40
...
...
@@ -48,18 +57,19 @@ const (
GASLIMIT
=
0x45
// 0x50 range - 'storage' and execution
POP
=
0x51
DUP
=
0x52
SWAP
=
0x53
MLOAD
=
0x54
MSTORE
=
0x55
MSTORE8
=
0x56
SLOAD
=
0x57
SSTORE
=
0x58
JUMP
=
0x59
JUMPI
=
0x5a
PC
=
0x5b
MSIZE
=
0x5c
POP
=
0x50
DUP
=
0x51
SWAP
=
0x52
MLOAD
=
0x53
MSTORE
=
0x54
MSTORE8
=
0x55
SLOAD
=
0x56
SSTORE
=
0x57
JUMP
=
0x58
JUMPI
=
0x59
PC
=
0x5a
MSIZE
=
0x5b
GAS
=
0x5c
// 0x60 range
PUSH1
=
0x60
...
...
@@ -120,6 +130,8 @@ var opCodeToString = map[OpCode]string{
NEG
:
"NEG"
,
LT
:
"LT"
,
GT
:
"GT"
,
SLT
:
"SLT"
,
SGT
:
"SGT"
,
EQ
:
"EQ"
,
NOT
:
"NOT"
,
...
...
@@ -140,6 +152,9 @@ var opCodeToString = map[OpCode]string{
CALLVALUE
:
"CALLVALUE"
,
CALLDATALOAD
:
"CALLDATALOAD"
,
CALLDATASIZE
:
"CALLDATASIZE"
,
CALLDATACOPY
:
"CALLDATACOPY"
,
CODESIZE
:
"CODESIZE"
,
CODECOPY
:
"CODECOPY"
,
GASPRICE
:
"TXGASPRICE"
,
// 0x40 range - block operations
...
...
@@ -162,6 +177,7 @@ var opCodeToString = map[OpCode]string{
JUMPI
:
"JUMPI"
,
PC
:
"PC"
,
MSIZE
:
"MSIZE"
,
GAS
:
"GAS"
,
// 0x60 range - push
PUSH1
:
"PUSH1"
,
...
...
@@ -208,7 +224,12 @@ var opCodeToString = map[OpCode]string{
}
func
(
o
OpCode
)
String
()
string
{
return
opCodeToString
[
o
]
str
:=
opCodeToString
[
o
]
if
len
(
str
)
==
0
{
return
fmt
.
Sprintf
(
"Missing opcode %#x"
,
int
(
o
))
}
return
str
}
// Op codes for assembling
...
...
ethchain/vm.go
View file @
5a0e7517
...
...
@@ -5,6 +5,7 @@ import (
"fmt"
"github.com/ethereum/eth-go/ethutil"
_
"github.com/obscuren/secp256k1-go"
"math"
_
"math"
"math/big"
)
...
...
@@ -18,6 +19,7 @@ var (
GasCreate
=
big
.
NewInt
(
100
)
GasCall
=
big
.
NewInt
(
20
)
GasMemory
=
big
.
NewInt
(
1
)
GasData
=
big
.
NewInt
(
5
)
GasTx
=
big
.
NewInt
(
500
)
)
...
...
@@ -112,15 +114,18 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro
}
gas
:=
new
(
big
.
Int
)
set
StepGasUsage
:=
func
(
amount
*
big
.
Int
)
{
add
StepGasUsage
:=
func
(
amount
*
big
.
Int
)
{
gas
.
Add
(
gas
,
amount
)
}
addStepGasUsage
(
GasStep
)
var
newMemSize
uint64
=
0
switch
op
{
case
S
HA3
:
setStepGasUsage
(
GasSha
)
case
S
TOP
:
case
SUICIDE
:
case
SLOAD
:
setStepGasUsage
(
GasSLoad
)
gas
.
Set
(
GasSLoad
)
case
SSTORE
:
var
mult
*
big
.
Int
y
,
x
:=
stack
.
Peekn
()
...
...
@@ -132,22 +137,55 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro
}
else
{
mult
=
ethutil
.
Big1
}
setStepGasUsage
(
new
(
big
.
Int
)
.
Mul
(
mult
,
GasSStore
)
)
gas
=
new
(
big
.
Int
)
.
Mul
(
mult
,
GasSStore
)
case
BALANCE
:
setStepGasUsage
(
GasBalance
)
case
CREATE
:
gas
.
Set
(
GasBalance
)
case
MSTORE
:
require
(
2
)
newMemSize
=
stack
.
Peek
()
.
Uint64
()
+
32
case
MLOAD
:
case
MSTORE8
:
require
(
2
)
newMemSize
=
stack
.
Peek
()
.
Uint64
()
+
1
case
RETURN
:
require
(
2
)
newMemSize
=
stack
.
Peek
()
.
Uint64
()
+
stack
.
data
[
stack
.
Len
()
-
2
]
.
Uint64
()
case
SHA3
:
require
(
2
)
gas
.
Set
(
GasSha
)
newMemSize
=
stack
.
Peek
()
.
Uint64
()
+
stack
.
data
[
stack
.
Len
()
-
2
]
.
Uint64
()
case
CALLDATACOPY
:
require
(
3
)
args
:=
stack
.
Get
(
big
.
NewInt
(
3
))
initSize
:=
new
(
big
.
Int
)
.
Add
(
args
[
1
],
args
[
0
])
newMemSize
=
stack
.
Peek
()
.
Uint64
()
+
stack
.
data
[
stack
.
Len
()
-
3
]
.
Uint64
()
case
CODECOPY
:
require
(
3
)
setStepGasUsage
(
CalculateTxGas
(
initSize
)
)
newMemSize
=
stack
.
Peek
()
.
Uint64
()
+
stack
.
data
[
stack
.
Len
()
-
3
]
.
Uint64
(
)
case
CALL
:
setStepGasUsage
(
GasCall
)
case
MLOAD
,
MSIZE
,
MSTORE8
,
MSTORE
:
setStepGasUsage
(
GasMemory
)
default
:
setStepGasUsage
(
GasStep
)
require
(
7
)
gas
.
Set
(
GasCall
)
addStepGasUsage
(
stack
.
data
[
stack
.
Len
()
-
2
])
x
:=
stack
.
data
[
stack
.
Len
()
-
6
]
.
Uint64
()
+
stack
.
data
[
stack
.
Len
()
-
7
]
.
Uint64
()
y
:=
stack
.
data
[
stack
.
Len
()
-
4
]
.
Uint64
()
+
stack
.
data
[
stack
.
Len
()
-
5
]
.
Uint64
()
newMemSize
=
uint64
(
math
.
Max
(
float64
(
x
),
float64
(
y
)))
case
CREATE
:
require
(
3
)
gas
.
Set
(
GasCreate
)
newMemSize
=
stack
.
data
[
stack
.
Len
()
-
2
]
.
Uint64
()
+
stack
.
data
[
stack
.
Len
()
-
3
]
.
Uint64
()
}
newMemSize
=
(
newMemSize
+
31
)
/
32
*
32
if
newMemSize
>
uint64
(
mem
.
Len
())
{
m
:=
GasMemory
.
Uint64
()
*
(
newMemSize
-
uint64
(
mem
.
Len
()))
/
32
addStepGasUsage
(
big
.
NewInt
(
int64
(
m
)))
}
if
!
closure
.
UseGas
(
gas
)
{
...
...
@@ -156,6 +194,8 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro
return
closure
.
Return
(
nil
),
fmt
.
Errorf
(
"insufficient gas %v %v"
,
closure
.
Gas
,
gas
)
}
mem
.
Resize
(
newMemSize
)
switch
op
{
case
LOG
:
stack
.
Print
()
...
...
@@ -320,7 +360,7 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro
case
ORIGIN
:
stack
.
Push
(
ethutil
.
BigD
(
vm
.
vars
.
Origin
))
case
CALLER
:
stack
.
Push
(
ethutil
.
BigD
(
closure
.
Callee
()
.
Address
()))
stack
.
Push
(
ethutil
.
BigD
(
closure
.
caller
.
Address
()))
case
CALLVALUE
:
stack
.
Push
(
vm
.
vars
.
Value
)
case
CALLDATALOAD
:
...
...
@@ -337,6 +377,26 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro
stack
.
Push
(
ethutil
.
BigD
(
data
))
case
CALLDATASIZE
:
stack
.
Push
(
big
.
NewInt
(
int64
(
len
(
closure
.
Args
))))
case
CALLDATACOPY
:
case
CODESIZE
:
case
CODECOPY
:
var
(
size
=
int64
(
len
(
closure
.
Script
))
mOff
=
stack
.
Pop
()
.
Int64
()
cOff
=
stack
.
Pop
()
.
Int64
()
l
=
stack
.
Pop
()
.
Int64
()
)
if
cOff
>
size
{
cOff
=
0
l
=
0
}
else
if
cOff
+
l
>
size
{
l
=
0
}
code
:=
closure
.
Script
[
cOff
:
cOff
+
l
]
mem
.
Set
(
mOff
,
l
,
code
)
case
GASPRICE
:
stack
.
Push
(
closure
.
Price
)
...
...
@@ -423,6 +483,8 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro
stack
.
Push
(
pc
)
case
MSIZE
:
stack
.
Push
(
big
.
NewInt
(
int64
(
mem
.
Len
())))
case
GAS
:
stack
.
Push
(
closure
.
Gas
)
// 0x60 range
case
CREATE
:
require
(
3
)
...
...
@@ -435,7 +497,7 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro
snapshot
:=
vm
.
state
.
Snapshot
()
// Generate a new address
addr
:=
ethutil
.
CreateAddress
(
closure
.
calle
e
.
Address
(),
closure
.
callee
.
N
())
addr
:=
ethutil
.
CreateAddress
(
closure
.
calle
r
.
Address
(),
closure
.
caller
.
N
())
// Create a new contract
contract
:=
NewContract
(
addr
,
value
,
[]
byte
(
""
))
// Set the init script
...
...
@@ -443,10 +505,10 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro
// Transfer all remaining gas to the new
// contract so it may run the init script
gas
:=
new
(
big
.
Int
)
.
Set
(
closure
.
Gas
)
closure
.
UseGas
(
gas
)
//
closure.UseGas(gas)
// Create the closure
c
:=
NewClosure
(
closure
.
calle
e
,
c
:=
NewClosure
(
closure
.
calle
r
,
closure
.
Object
(),
contract
.
initScript
,
vm
.
state
,
...
...
@@ -467,6 +529,7 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro
vm
.
state
.
UpdateStateObject
(
contract
)
}
case
CALL
:
// TODO RE-WRITE
require
(
7
)
// Closure addr
addr
:=
stack
.
Pop
()
...
...
@@ -476,30 +539,22 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro
inSize
,
inOffset
:=
stack
.
Popn
()
// Pop return size and offset
retSize
,
retOffset
:=
stack
.
Popn
()
// Make sure there's enough gas
if
closure
.
Gas
.
Cmp
(
gas
)
<
0
{
stack
.
Push
(
ethutil
.
BigFalse
)
break
}
// Get the arguments from the memory
args
:=
mem
.
Get
(
inOffset
.
Int64
(),
inSize
.
Int64
())
snapshot
:=
vm
.
state
.
Snapshot
()
closure
.
object
.
Nonce
+=
1
if
closure
.
object
.
Amount
.
Cmp
(
value
)
<
0
{
ethutil
.
Config
.
Log
.
Debugf
(
"Insufficient funds to transfer value. Req %v, has %v"
,
value
,
closure
.
object
.
Amount
)
stack
.
Push
(
ethutil
.
BigFalse
)
}
else
{
// Fetch the contract which will serve as the closure body
contract
:=
vm
.
state
.
GetStateObject
(
addr
.
Bytes
())
if
contract
!=
nil
{
// Prepay for the gas
// If gas is set to 0 use all remaining gas for the next call
if
gas
.
Cmp
(
big
.
NewInt
(
0
))
==
0
{
// Copy
gas
=
new
(
big
.
Int
)
.
Set
(
closure
.
Gas
)
}
closure
.
UseGas
(
gas
)
// Add the value to the state object
contract
.
AddAmount
(
value
)
...
...
@@ -522,6 +577,7 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro
ethutil
.
Config
.
Log
.
Debugf
(
"Contract %x not found
\n
"
,
addr
.
Bytes
())
stack
.
Push
(
ethutil
.
BigFalse
)
}
}
case
RETURN
:
require
(
2
)
size
,
offset
:=
stack
.
Popn
()
...
...
ethminer/miner.go
View file @
5a0e7517
...
...
@@ -136,11 +136,21 @@ func (self *Miner) mineNewBlock() {
// Sort the transactions by nonce in case of odd network propagation
sort
.
Sort
(
ethchain
.
TxByNonce
{
self
.
txs
})
// Accumulate all valid transaction and apply them to the new state
receipts
,
txs
:=
stateManager
.
ApplyTransactions
(
self
.
block
.
State
(),
self
.
block
,
self
.
txs
)
self
.
txs
=
txs
// Error may be ignored. It's not important during mining
parent
:=
self
.
ethereum
.
BlockChain
()
.
GetBlock
(
self
.
block
.
PrevHash
)
coinbase
:=
self
.
block
.
State
()
.
GetOrNewStateObject
(
self
.
block
.
Coinbase
)
coinbase
.
SetGasPool
(
self
.
block
.
CalcGasLimit
(
parent
))
receipts
,
txs
,
unhandledTxs
,
err
:=
stateManager
.
ProcessTransactions
(
coinbase
,
self
.
block
.
State
(),
self
.
block
,
self
.
block
,
self
.
txs
)
if
err
!=
nil
{
ethutil
.
Config
.
Log
.
Debugln
(
"[MINER]"
,
err
)
}
self
.
txs
=
append
(
txs
,
unhandledTxs
...
)
// Set the transactions to the block so the new SHA3 can be calculated
self
.
block
.
SetReceipts
(
receipts
,
txs
)
// Accumulate the rewards included for this block
stateManager
.
AccumelateRewards
(
self
.
block
.
State
(),
self
.
block
)
...
...
@@ -155,6 +165,7 @@ func (self *Miner) mineNewBlock() {
}
else
{
self
.
ethereum
.
Broadcast
(
ethwire
.
MsgBlockTy
,
[]
interface
{}{
self
.
block
.
Value
()
.
Val
})
ethutil
.
Config
.
Log
.
Infof
(
"[MINER] 🔨 Mined block %x
\n
"
,
self
.
block
.
Hash
())
ethutil
.
Config
.
Log
.
Infoln
(
self
.
block
)
// Gather the new batch of transactions currently in the tx pool
self
.
txs
=
self
.
ethereum
.
TxPool
()
.
CurrentTransactions
()
}
...
...
ethpub/pub.go
View file @
5a0e7517
...
...
@@ -115,9 +115,13 @@ var namereg = ethutil.FromHex("bb5f186604d057c1c5240ca2ae0f6430138ac010")
func
GetAddressFromNameReg
(
stateManager
*
ethchain
.
StateManager
,
name
string
)
[]
byte
{
recp
:=
new
(
big
.
Int
)
.
SetBytes
([]
byte
(
name
))
object
:=
stateManager
.
CurrentState
()
.
GetStateObject
(
namereg
)
if
object
!=
nil
{
reg
:=
object
.
GetStorage
(
recp
)
return
reg
.
Bytes
()
}
return
nil
}
func
(
lib
*
PEthereum
)
createTx
(
key
,
recipient
,
valueStr
,
gasStr
,
gasPriceStr
,
scriptStr
string
)
(
*
PReceipt
,
error
)
{
...
...
@@ -193,8 +197,6 @@ func (lib *PEthereum) createTx(key, recipient, valueStr, gasStr, gasPriceStr, sc
if
contractCreation
{
ethutil
.
Config
.
Log
.
Infof
(
"Contract addr %x"
,
tx
.
CreationAddress
())
}
else
{
ethutil
.
Config
.
Log
.
Infof
(
"Tx hash %x"
,
tx
.
Hash
())
}
return
NewPReciept
(
contractCreation
,
tx
.
CreationAddress
(),
tx
.
Hash
(),
keyPair
.
Address
()),
nil
...
...
ethpub/types.go
View file @
5a0e7517
...
...
@@ -46,6 +46,8 @@ type PBlock struct {
Transactions
string
`json:"transactions"`
Time
int64
`json:"time"`
Coinbase
string
`json:"coinbase"`
GasLimit
string
`json:"gasLimit"`
GasUsed
string
`json:"gasUsed"`
}
// Creates a new QML Block from a chain block
...
...
@@ -64,7 +66,7 @@ func NewPBlock(block *ethchain.Block) *PBlock {
return
nil
}
return
&
PBlock
{
ref
:
block
,
Number
:
int
(
block
.
Number
.
Uint64
()),
Hash
:
ethutil
.
Hex
(
block
.
Hash
()),
Transactions
:
string
(
txJson
),
Time
:
block
.
Time
,
Coinbase
:
ethutil
.
Hex
(
block
.
Coinbase
)}
return
&
PBlock
{
ref
:
block
,
Number
:
int
(
block
.
Number
.
Uint64
()),
GasUsed
:
block
.
GasUsed
.
String
(),
GasLimit
:
block
.
GasLimit
.
String
(),
Hash
:
ethutil
.
Hex
(
block
.
Hash
()),
Transactions
:
string
(
txJson
),
Time
:
block
.
Time
,
Coinbase
:
ethutil
.
Hex
(
block
.
Coinbase
)}
}
func
(
self
*
PBlock
)
ToString
()
string
{
...
...
@@ -109,11 +111,12 @@ func NewPTx(tx *ethchain.Transaction) *PTx {
sender
:=
hex
.
EncodeToString
(
tx
.
Sender
())
createsContract
:=
tx
.
CreatesContract
()
data
:=
strings
.
Join
(
ethchain
.
Disassemble
(
tx
.
Data
),
"
\n
"
)
isContract
:=
len
(
tx
.
Data
)
>
0
data
:=
string
(
tx
.
Data
)
if
tx
.
CreatesContract
()
{
data
=
strings
.
Join
(
ethchain
.
Disassemble
(
tx
.
Data
),
"
\n
"
)
}
return
&
PTx
{
ref
:
tx
,
Hash
:
hash
,
Value
:
ethutil
.
CurrencyToString
(
tx
.
Value
),
Address
:
receiver
,
Contract
:
isContract
,
Gas
:
tx
.
Gas
.
String
(),
GasPrice
:
tx
.
GasPrice
.
String
(),
Data
:
data
,
Sender
:
sender
,
CreatesContract
:
createsContract
,
RawData
:
hex
.
EncodeToString
(
tx
.
Data
)}
return
&
PTx
{
ref
:
tx
,
Hash
:
hash
,
Value
:
ethutil
.
CurrencyToString
(
tx
.
Value
),
Address
:
receiver
,
Contract
:
tx
.
CreatesContract
()
,
Gas
:
tx
.
Gas
.
String
(),
GasPrice
:
tx
.
GasPrice
.
String
(),
Data
:
data
,
Sender
:
sender
,
CreatesContract
:
createsContract
,
RawData
:
hex
.
EncodeToString
(
tx
.
Data
)}
}
func
(
self
*
PTx
)
ToString
()
string
{
...
...
ethutil/big.go
View file @
5a0e7517
...
...
@@ -68,8 +68,8 @@ func BigCopy(src *big.Int) *big.Int {
// Returns the maximum size big integer
func
BigMax
(
x
,
y
*
big
.
Int
)
*
big
.
Int
{
if
x
.
Cmp
(
y
)
<=
0
{
return
x
return
y
}
return
y
return
x
}
ethutil/common.go
View file @
5a0e7517
...
...
@@ -18,8 +18,8 @@ var (
Wei
=
big
.
NewInt
(
1
)
)
// Currency to string
//
// Currency to string
// Returns a string representing a human readable format
func
CurrencyToString
(
num
*
big
.
Int
)
string
{
switch
{
...
...
@@ -47,7 +47,7 @@ func CurrencyToString(num *big.Int) string {
// Common big integers often used
var
(
Big1
=
big
.
NewInt
(
1
)
Big2
=
big
.
NewInt
(
1
)
Big2
=
big
.
NewInt
(
2
)
Big0
=
big
.
NewInt
(
0
)
Big32
=
big
.
NewInt
(
32
)
Big256
=
big
.
NewInt
(
0xff
)
...
...
ethutil/config.go
View file @
5a0e7517
...
...
@@ -75,11 +75,11 @@ func ReadConfig(base string, logTypes LoggerType, g *globalconf.GlobalConf, id s
if
Config
==
nil
{
path
:=
ApplicationFolder
(
base
)
Config
=
&
config
{
ExecPath
:
path
,
Debug
:
true
,
Ver
:
"0.5.
0 RC12
"
}
Config
=
&
config
{
ExecPath
:
path
,
Debug
:
true
,
Ver
:
"0.5.
13
"
}
Config
.
conf
=
g
Config
.
Identifier
=
id
Config
.
Log
=
NewLogger
(
logTypes
,
LogLevelDebug
)
Config
.
SetClientString
(
"
/
Ethereum(G)"
)
Config
.
SetClientString
(
"Ethereum(G)"
)
}
return
Config
...
...
@@ -88,11 +88,9 @@ func ReadConfig(base string, logTypes LoggerType, g *globalconf.GlobalConf, id s
// Set client string
//
func
(
c
*
config
)
SetClientString
(
str
string
)
{
id
:=
runtime
.
GOOS
if
len
(
c
.
Identifier
)
>
0
{
id
=
c
.
Identifier
}
Config
.
ClientString
=
fmt
.
Sprintf
(
"%s nv%s/%s"
,
str
,
c
.
Ver
,
id
)
os
:=
runtime
.
GOOS
cust
:=
c
.
Identifier
Config
.
ClientString
=
fmt
.
Sprintf
(
"%s/v%s/%s/%s/Go"
,
str
,
c
.
Ver
,
cust
,
os
)
}
func
(
c
*
config
)
SetIdentifier
(
id
string
)
{
...
...
@@ -145,12 +143,17 @@ func NewLogger(flag LoggerType, level int) *Logger {
return
&
Logger
{
logSys
:
loggers
,
logLevel
:
level
}
}
func
(
self
*
Logger
)
SetLevel
(
level
int
)
{
self
.
logLevel
=
level
}
func
(
log
*
Logger
)
AddLogSystem
(
logger
LogSystem
)
{
log
.
logSys
=
append
(
log
.
logSys
,
logger
)
}
const
(
LogLevelDebug
=
iota
LogLevelSystem
=
iota
LogLevelDebug
LogLevelInfo
)
...
...
@@ -206,6 +209,26 @@ func (log *Logger) Fatal(v ...interface{}) {
os
.
Exit
(
1
)
}
func
(
log
*
Logger
)
Println
(
level
int
,
v
...
interface
{})
{
if
log
.
logLevel
>
level
{
return
}
for
_
,
logger
:=
range
log
.
logSys
{
logger
.
Println
(
v
...
)
}
}
func
(
log
*
Logger
)
Printf
(
level
int
,
format
string
,
v
...
interface
{})
{
if
log
.
logLevel
>
level
{
return
}
for
_
,
logger
:=
range
log
.
logSys
{
logger
.
Printf
(
format
,
v
...
)
}
}
type
confValue
struct
{
value
string
}
...
...
ethutil/keypair.go
View file @
5a0e7517
...
...
@@ -12,6 +12,12 @@ type KeyPair struct {
account
*
StateObject
}
func
GenerateNewKeyPair
()
(
*
KeyPair
,
error
)
{
_
,
prv
:=
secp256k1
.
GenerateKeyPair
()
return
NewKeyPairFromSec
(
prv
)
}
func
NewKeyPairFromSec
(
seckey
[]
byte
)
(
*
KeyPair
,
error
)
{
pubkey
,
err
:=
secp256k1
.
GeneratePubKey
(
seckey
)
if
err
!=
nil
{
...
...
ethutil/rlp.go
View file @
5a0e7517
...
...
@@ -11,6 +11,7 @@ import (
type
RlpEncodable
interface
{
RlpEncode
()
[]
byte
RlpValue
()
[]
interface
{}
}
type
RlpEncoder
struct
{
...
...
ethwire/messaging.go
View file @
5a0e7517
// Package ethwire provides low level access to the Ethereum network and allows
// you to broadcast data over the network.
package
ethwire
import
(
...
...
@@ -9,11 +11,13 @@ import (
"time"
)
// Message:
// [4 bytes token] RLP([TYPE, DATA])
// Refer to http://wiki.ethereum.org/index.php/Wire_Protocol
// Connection interface describing the methods required to implement the wire protocol.
type
Conn
interface
{
Write
(
typ
MsgType
,
v
...
interface
{})
error
Read
()
*
Msg
}
// The magic token which should be the first 4 bytes of every message.
// The magic token which should be the first 4 bytes of every message
and can be used as separator between messages
.
var
MagicToken
=
[]
byte
{
34
,
64
,
8
,
145
}
type
MsgType
byte
...
...
@@ -68,6 +72,157 @@ func NewMessage(msgType MsgType, data interface{}) *Msg {
}
}
type
Messages
[]
*
Msg
// The connection object allows you to set up a connection to the Ethereum network.
// The Connection object takes care of all encoding and sending objects properly over
// the network.
type
Connection
struct
{
conn
net
.
Conn
nTimeout
time
.
Duration
pendingMessages
Messages
}
// Create a new connection to the Ethereum network
func
New
(
conn
net
.
Conn
)
*
Connection
{
return
&
Connection
{
conn
:
conn
,
nTimeout
:
500
}
}
// Read, reads from the network. It will block until the next message is received.
func
(
self
*
Connection
)
Read
()
*
Msg
{
if
len
(
self
.
pendingMessages
)
==
0
{
self
.
readMessages
()
}
ret
:=
self
.
pendingMessages
[
0
]
self
.
pendingMessages
=
self
.
pendingMessages
[
1
:
]
return
ret
}
// Write to the Ethereum network specifying the type of the message and
// the data. Data can be of type RlpEncodable or []interface{}. Returns
// nil or if something went wrong an error.
func
(
self
*
Connection
)
Write
(
typ
MsgType
,
v
...
interface
{})
error
{
var
pack
[]
byte
slice
:=
[][]
interface
{}{[]
interface
{}{
byte
(
typ
)}}
for
_
,
value
:=
range
v
{
if
encodable
,
ok
:=
value
.
(
ethutil
.
RlpEncodable
);
ok
{
slice
=
append
(
slice
,
encodable
.
RlpValue
())
}
else
if
raw
,
ok
:=
value
.
([]
interface
{});
ok
{
slice
=
append
(
slice
,
raw
)
}
else
{
panic
(
fmt
.
Sprintf
(
"Unable to 'write' object of type %T"
,
value
))
}
}
// Encode the type and the (RLP encoded) data for sending over the wire
encoded
:=
ethutil
.
NewValue
(
slice
)
.
Encode
()
payloadLength
:=
ethutil
.
NumberToBytes
(
uint32
(
len
(
encoded
)),
32
)
// Write magic token and payload length (first 8 bytes)
pack
=
append
(
MagicToken
,
payloadLength
...
)
pack
=
append
(
pack
,
encoded
...
)
// Write to the connection
_
,
err
:=
self
.
conn
.
Write
(
pack
)
if
err
!=
nil
{
return
err
}
return
nil
}
func
(
self
*
Connection
)
readMessage
(
data
[]
byte
)
(
msg
*
Msg
,
remaining
[]
byte
,
done
bool
,
err
error
)
{
if
len
(
data
)
==
0
{
return
nil
,
nil
,
true
,
nil
}
if
len
(
data
)
<=
8
{
return
nil
,
remaining
,
false
,
errors
.
New
(
"Invalid message"
)
}
// Check if the received 4 first bytes are the magic token
if
bytes
.
Compare
(
MagicToken
,
data
[
:
4
])
!=
0
{
return
nil
,
nil
,
false
,
fmt
.
Errorf
(
"MagicToken mismatch. Received %v"
,
data
[
:
4
])
}
messageLength
:=
ethutil
.
BytesToNumber
(
data
[
4
:
8
])
remaining
=
data
[
8
+
messageLength
:
]
if
int
(
messageLength
)
>
len
(
data
[
8
:
])
{
return
nil
,
nil
,
false
,
fmt
.
Errorf
(
"message length %d, expected %d"
,
len
(
data
[
8
:
]),
messageLength
)
}
message
:=
data
[
8
:
8
+
messageLength
]
decoder
:=
ethutil
.
NewValueFromBytes
(
message
)
// Type of message
t
:=
decoder
.
Get
(
0
)
.
Uint
()
// Actual data
d
:=
decoder
.
SliceFrom
(
1
)
msg
=
&
Msg
{
Type
:
MsgType
(
t
),
Data
:
d
,
}
return
}
// The basic message reader waits for data on the given connection, decoding
// and doing a few sanity checks such as if there's a data type and
// unmarhals the given data
func
(
self
*
Connection
)
readMessages
()
(
err
error
)
{
// The recovering function in case anything goes horribly wrong
defer
func
()
{
if
r
:=
recover
();
r
!=
nil
{
err
=
fmt
.
Errorf
(
"ethwire.ReadMessage error: %v"
,
r
)
}
}()
// Buff for writing network message to
//buff := make([]byte, 1440)
var
buff
[]
byte
var
totalBytes
int
for
{
// Give buffering some time
self
.
conn
.
SetReadDeadline
(
time
.
Now
()
.
Add
(
self
.
nTimeout
*
time
.
Millisecond
))
// Create a new temporarily buffer
b
:=
make
([]
byte
,
1440
)
// Wait for a message from this peer
n
,
_
:=
self
.
conn
.
Read
(
b
)
if
err
!=
nil
&&
n
==
0
{
if
err
.
Error
()
!=
"EOF"
{
fmt
.
Println
(
"err now"
,
err
)
return
err
}
else
{
break
}
// Messages can't be empty
}
else
if
n
==
0
{
break
}
buff
=
append
(
buff
,
b
[
:
n
]
...
)
totalBytes
+=
n
}
// Reslice buffer
buff
=
buff
[
:
totalBytes
]
msg
,
remaining
,
done
,
err
:=
self
.
readMessage
(
buff
)
for
;
done
!=
true
;
msg
,
remaining
,
done
,
err
=
self
.
readMessage
(
remaining
)
{
//log.Println("rx", msg)
if
msg
!=
nil
{
self
.
pendingMessages
=
append
(
self
.
pendingMessages
,
msg
)
}
}
return
}
func
ReadMessage
(
data
[]
byte
)
(
msg
*
Msg
,
remaining
[]
byte
,
done
bool
,
err
error
)
{
if
len
(
data
)
==
0
{
return
nil
,
nil
,
true
,
nil
...
...
peer.go
View file @
5a0e7517
...
...
@@ -17,7 +17,9 @@ const (
// The size of the output buffer for writing messages
outputBufferSize
=
50
// Current protocol version
ProtocolVersion
=
17
ProtocolVersion
=
20
// Interval for ping/pong message
pingPongTimer
=
2
*
time
.
Second
)
type
DiscReason
byte
...
...
@@ -151,11 +153,11 @@ func NewPeer(conn net.Conn, ethereum *Ethereum, inbound bool) *Peer {
pubkey
:
pubkey
,
blocksRequested
:
10
,
caps
:
ethereum
.
ServerCaps
(),
version
:
ethutil
.
Config
.
ClientString
,
}
}
func
NewOutboundPeer
(
addr
string
,
ethereum
*
Ethereum
,
caps
Caps
)
*
Peer
{
p
:=
&
Peer
{
outputQueue
:
make
(
chan
*
ethwire
.
Msg
,
outputBufferSize
),
quit
:
make
(
chan
bool
),
...
...
@@ -241,9 +243,11 @@ func (p *Peer) writeMessage(msg *ethwire.Msg) {
}
}
ethutil
.
Config
.
Log
.
Println
(
ethutil
.
LogLevelSystem
,
"<="
,
msg
.
Type
,
msg
.
Data
)
err
:=
ethwire
.
WriteMessage
(
p
.
conn
,
msg
)
if
err
!=
nil
{
ethutil
.
Config
.
Log
.
Debugln
(
"Can't send message:"
,
err
)
ethutil
.
Config
.
Log
.
Debugln
(
"
[PEER]
Can't send message:"
,
err
)
// Stop the client if there was an error writing to it
p
.
Stop
()
return
...
...
@@ -253,7 +257,7 @@ func (p *Peer) writeMessage(msg *ethwire.Msg) {
// Outbound message handler. Outbound messages are handled here
func
(
p
*
Peer
)
HandleOutbound
()
{
// The ping timer. Makes sure that every 2 minutes a ping is send to the peer
pingTimer
:=
time
.
NewTicker
(
30
*
time
.
Second
)
pingTimer
:=
time
.
NewTicker
(
pingPongTimer
)
serviceTimer
:=
time
.
NewTicker
(
5
*
time
.
Minute
)
out
:
...
...
@@ -264,8 +268,14 @@ out:
p
.
writeMessage
(
msg
)
p
.
lastSend
=
time
.
Now
()
// Ping timer
sends a ping to the peer each 2 minutes
// Ping timer
case
<-
pingTimer
.
C
:
timeSince
:=
time
.
Since
(
time
.
Unix
(
p
.
lastPong
,
0
))
if
!
p
.
pingStartTime
.
IsZero
()
&&
p
.
lastPong
!=
0
&&
timeSince
>
(
pingPongTimer
+
30
*
time
.
Second
)
{
ethutil
.
Config
.
Log
.
Infof
(
"[PEER] Peer did not respond to latest pong fast enough, it took %s, disconnecting.
\n
"
,
timeSince
)
p
.
Stop
()
return
}
p
.
writeMessage
(
ethwire
.
NewMessage
(
ethwire
.
MsgPingTy
,
""
))
p
.
pingStartTime
=
time
.
Now
()
...
...
@@ -307,6 +317,8 @@ func (p *Peer) HandleInbound() {
ethutil
.
Config
.
Log
.
Debugln
(
err
)
}
for
_
,
msg
:=
range
msgs
{
ethutil
.
Config
.
Log
.
Println
(
ethutil
.
LogLevelSystem
,
"=>"
,
msg
.
Type
,
msg
.
Data
)
switch
msg
.
Type
{
case
ethwire
.
MsgHandshakeTy
:
// Version message
...
...
@@ -393,7 +405,7 @@ func (p *Peer) HandleInbound() {
if
err
!=
nil
{
// If the parent is unknown try to catch up with this peer
if
ethchain
.
IsParentErr
(
err
)
{
ethutil
.
Config
.
Log
.
Infoln
(
"Attempting to catch
up since we don't know the parent
"
)
ethutil
.
Config
.
Log
.
Infoln
(
"Attempting to catch
. Parent known
"
)
p
.
catchingUp
=
false
p
.
CatchupWithPeer
(
p
.
ethereum
.
BlockChain
()
.
CurrentBlock
.
Hash
())
}
else
if
ethchain
.
IsValidationErr
(
err
)
{
...
...
@@ -405,7 +417,7 @@ func (p *Peer) HandleInbound() {
if
p
.
catchingUp
&&
msg
.
Data
.
Len
()
>
1
{
if
lastBlock
!=
nil
{
blockInfo
:=
lastBlock
.
BlockInfo
()
ethutil
.
Config
.
Log
.
Debugf
(
"Synced
to block height
#%d %x %x
\n
"
,
blockInfo
.
Number
,
lastBlock
.
Hash
(),
blockInfo
.
Hash
)
ethutil
.
Config
.
Log
.
Debugf
(
"Synced
chain to
#%d %x %x
\n
"
,
blockInfo
.
Number
,
lastBlock
.
Hash
(),
blockInfo
.
Hash
)
}
p
.
catchingUp
=
false
...
...
@@ -571,7 +583,7 @@ func (p *Peer) pushHandshake() error {
pubkey
:=
keyRing
.
PublicKey
msg
:=
ethwire
.
NewMessage
(
ethwire
.
MsgHandshakeTy
,
[]
interface
{}{
uint32
(
ProtocolVersion
),
uint32
(
0
),
p
.
version
,
byte
(
p
.
caps
),
p
.
port
,
pubkey
[
1
:
],
uint32
(
ProtocolVersion
),
uint32
(
0
),
[]
byte
(
p
.
version
)
,
byte
(
p
.
caps
),
p
.
port
,
pubkey
[
1
:
],
})
p
.
QueueMessage
(
msg
)
...
...
@@ -603,7 +615,7 @@ func (p *Peer) handleHandshake(msg *ethwire.Msg) {
c
:=
msg
.
Data
if
c
.
Get
(
0
)
.
Uint
()
!=
ProtocolVersion
{
ethutil
.
Config
.
Log
.
Debug
ln
(
"Invalid peer version. Require protocol:"
,
ProtocolVersion
)
ethutil
.
Config
.
Log
.
Debug
f
(
"Invalid peer version. Require protocol: %d. Received: %d
\n
"
,
ProtocolVersion
,
c
.
Get
(
0
)
.
Uint
()
)
p
.
Stop
()
return
}
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment