Moved logging to state, proper structured block
* Moved logs to state so it's subject to snapshotting * Split up block header * Removed logs from transactions and made them receipts only
This commit is contained in:
		| @@ -149,10 +149,7 @@ func (block *Block) Hash() ethutil.Bytes { | |||||||
| } | } | ||||||
|  |  | ||||||
| func (block *Block) HashNoNonce() []byte { | func (block *Block) HashNoNonce() []byte { | ||||||
| 	return ethcrypto.Sha3(ethutil.Encode([]interface{}{block.PrevHash, | 	return ethcrypto.Sha3(ethutil.Encode(block.miningHeader())) | ||||||
| 		block.UncleSha, block.Coinbase, block.state.Trie.Root, |  | ||||||
| 		block.ReceiptSha, block.Difficulty, block.Number, block.MinGasPrice, |  | ||||||
| 		block.GasLimit, block.GasUsed, block.Time, block.Extra})) |  | ||||||
| } | } | ||||||
|  |  | ||||||
| func (block *Block) State() *ethstate.State { | func (block *Block) State() *ethstate.State { | ||||||
| @@ -235,31 +232,18 @@ func (block *Block) rlpUncles() interface{} { | |||||||
|  |  | ||||||
| func (block *Block) SetUncles(uncles []*Block) { | func (block *Block) SetUncles(uncles []*Block) { | ||||||
| 	block.Uncles = uncles | 	block.Uncles = uncles | ||||||
|  |  | ||||||
| 	block.UncleSha = ethcrypto.Sha3(ethutil.Encode(block.rlpUncles())) | 	block.UncleSha = ethcrypto.Sha3(ethutil.Encode(block.rlpUncles())) | ||||||
| } | } | ||||||
|  |  | ||||||
| func (self *Block) SetReceipts(receipts Receipts) { | func (self *Block) SetReceipts(receipts Receipts) { | ||||||
| 	self.receipts = receipts | 	self.receipts = receipts | ||||||
| 	self.SetReceiptHash(receipts) | 	self.ReceiptSha = DeriveSha(receipts) | ||||||
|  | 	self.LogsBloom = CreateBloom(self) | ||||||
| } | } | ||||||
|  |  | ||||||
| func (self *Block) SetTransactions(txs Transactions) { | func (self *Block) SetTransactions(txs Transactions) { | ||||||
| 	self.setTransactions(txs) | 	self.transactions = txs | ||||||
| 	self.SetTransactionHash(txs) | 	self.TxSha = DeriveSha(txs) | ||||||
| } |  | ||||||
|  |  | ||||||
| func (block *Block) setTransactions(txs Transactions) { |  | ||||||
| 	block.transactions = txs |  | ||||||
| 	block.LogsBloom = CreateBloom(block) |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func (self *Block) SetTransactionHash(transactions Transactions) { |  | ||||||
| 	self.TxSha = DeriveSha(transactions) |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func (self *Block) SetReceiptHash(receipts Receipts) { |  | ||||||
| 	self.ReceiptSha = DeriveSha(receipts) |  | ||||||
| } | } | ||||||
|  |  | ||||||
| func (block *Block) Value() *ethutil.Value { | func (block *Block) Value() *ethutil.Value { | ||||||
| @@ -285,10 +269,10 @@ func (block *Block) RlpValueDecode(decoder *ethutil.Value) { | |||||||
| 	if decoder.Get(1).IsNil() == false { // Yes explicitness | 	if decoder.Get(1).IsNil() == false { // Yes explicitness | ||||||
| 		//receipts := decoder.Get(1) | 		//receipts := decoder.Get(1) | ||||||
| 		//block.receipts = make([]*Receipt, receipts.Len()) | 		//block.receipts = make([]*Receipt, receipts.Len()) | ||||||
| 		it := decoder.Get(1).NewIterator() | 		txs := decoder.Get(1) | ||||||
| 		block.transactions = make(Transactions, it.Len()) | 		block.transactions = make(Transactions, txs.Len()) | ||||||
| 		for it.Next() { | 		for i := 0; i < txs.Len(); i++ { | ||||||
| 			block.transactions[it.Idx()] = NewTransactionFromValue(it.Value()) | 			block.transactions[i] = NewTransactionFromValue(txs.Get(i)) | ||||||
| 			//receipt := NewRecieptFromValue(receipts.Get(i)) | 			//receipt := NewRecieptFromValue(receipts.Get(i)) | ||||||
| 			//block.transactions[i] = receipt.Tx | 			//block.transactions[i] = receipt.Tx | ||||||
| 			//block.receipts[i] = receipt | 			//block.receipts[i] = receipt | ||||||
| @@ -347,7 +331,7 @@ func (self *Block) Receipts() []*Receipt { | |||||||
| 	return self.receipts | 	return self.receipts | ||||||
| } | } | ||||||
|  |  | ||||||
| func (block *Block) header() []interface{} { | func (block *Block) miningHeader() []interface{} { | ||||||
| 	return []interface{}{ | 	return []interface{}{ | ||||||
| 		// Sha of the previous block | 		// Sha of the previous block | ||||||
| 		block.PrevHash, | 		block.PrevHash, | ||||||
| @@ -377,11 +361,13 @@ func (block *Block) header() []interface{} { | |||||||
| 		block.Time, | 		block.Time, | ||||||
| 		// Extra data | 		// Extra data | ||||||
| 		block.Extra, | 		block.Extra, | ||||||
| 		// Block's Nonce for validation |  | ||||||
| 		block.Nonce, |  | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
|  |  | ||||||
|  | func (block *Block) header() []interface{} { | ||||||
|  | 	return append(block.miningHeader(), block.Nonce) | ||||||
|  | } | ||||||
|  |  | ||||||
| func (block *Block) String() string { | func (block *Block) String() string { | ||||||
| 	return fmt.Sprintf(` | 	return fmt.Sprintf(` | ||||||
| 	BLOCK(%x): Size: %v | 	BLOCK(%x): Size: %v | ||||||
|   | |||||||
| @@ -3,21 +3,21 @@ package ethchain | |||||||
| import ( | import ( | ||||||
| 	"math/big" | 	"math/big" | ||||||
|  |  | ||||||
|  | 	"github.com/ethereum/go-ethereum/ethstate" | ||||||
| 	"github.com/ethereum/go-ethereum/ethutil" | 	"github.com/ethereum/go-ethereum/ethutil" | ||||||
| 	"github.com/ethereum/go-ethereum/vm" |  | ||||||
| ) | ) | ||||||
|  |  | ||||||
| func CreateBloom(block *Block) []byte { | func CreateBloom(block *Block) []byte { | ||||||
| 	bin := new(big.Int) | 	bin := new(big.Int) | ||||||
| 	bin.Or(bin, bloom9(block.Coinbase)) | 	bin.Or(bin, bloom9(block.Coinbase)) | ||||||
| 	for _, tx := range block.Transactions() { | 	for _, receipt := range block.Receipts() { | ||||||
| 		bin.Or(bin, LogsBloom(tx.logs)) | 		bin.Or(bin, LogsBloom(receipt.logs)) | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	return bin.Bytes() | 	return bin.Bytes() | ||||||
| } | } | ||||||
|  |  | ||||||
| func LogsBloom(logs []vm.Log) *big.Int { | func LogsBloom(logs ethstate.Logs) *big.Int { | ||||||
| 	bin := new(big.Int) | 	bin := new(big.Int) | ||||||
| 	for _, log := range logs { | 	for _, log := range logs { | ||||||
| 		data := [][]byte{log.Address} | 		data := [][]byte{log.Address} | ||||||
|   | |||||||
| @@ -145,6 +145,9 @@ func (self *StateManager) ProcessTransactions(coinbase *ethstate.StateObject, st | |||||||
|  |  | ||||||
| done: | done: | ||||||
| 	for i, tx := range txs { | 	for i, tx := range txs { | ||||||
|  | 		// If we are mining this block and validating we want to set the logs back to 0 | ||||||
|  | 		state.EmptyLogs() | ||||||
|  |  | ||||||
| 		txGas := new(big.Int).Set(tx.Gas) | 		txGas := new(big.Int).Set(tx.Gas) | ||||||
|  |  | ||||||
| 		cb := state.GetStateObject(coinbase.Address()) | 		cb := state.GetStateObject(coinbase.Address()) | ||||||
| @@ -175,7 +178,7 @@ done: | |||||||
| 		txGas.Sub(txGas, st.gas) | 		txGas.Sub(txGas, st.gas) | ||||||
| 		cumulative := new(big.Int).Set(totalUsedGas.Add(totalUsedGas, txGas)) | 		cumulative := new(big.Int).Set(totalUsedGas.Add(totalUsedGas, txGas)) | ||||||
| 		//receipt := &Receipt{tx, ethutil.CopyBytes(state.Root().([]byte)), accumelative} | 		//receipt := &Receipt{tx, ethutil.CopyBytes(state.Root().([]byte)), accumelative} | ||||||
| 		receipt := &Receipt{ethutil.CopyBytes(state.Root().([]byte)), cumulative, LogsBloom(tx.logs).Bytes(), tx.logs} | 		receipt := &Receipt{ethutil.CopyBytes(state.Root().([]byte)), cumulative, LogsBloom(state.Logs()).Bytes(), state.Logs()} | ||||||
|  |  | ||||||
| 		if i < len(block.Receipts()) { | 		if i < len(block.Receipts()) { | ||||||
| 			original := block.Receipts()[i] | 			original := block.Receipts()[i] | ||||||
| @@ -238,7 +241,7 @@ func (sm *StateManager) Process(block *Block) (err error) { | |||||||
|  |  | ||||||
| 	txSha := DeriveSha(block.transactions) | 	txSha := DeriveSha(block.transactions) | ||||||
| 	if bytes.Compare(txSha, block.TxSha) != 0 { | 	if bytes.Compare(txSha, block.TxSha) != 0 { | ||||||
| 		return fmt.Errorf("Error validating transaction sha. Received %x, got %x", block.ReceiptSha, txSha) | 		return fmt.Errorf("Error validating transaction sha. Received %x, got %x", block.TxSha, txSha) | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	receipts, err := sm.ApplyDiff(state, parent, block) | 	receipts, err := sm.ApplyDiff(state, parent, block) | ||||||
|   | |||||||
| @@ -232,7 +232,7 @@ func (self *StateTransition) TransitionState() (err error) { | |||||||
| 		} else { | 		} else { | ||||||
| 			// Add default LOG. Default = big(sender.addr) + 1 | 			// Add default LOG. Default = big(sender.addr) + 1 | ||||||
| 			addr := ethutil.BigD(receiver.Address()) | 			addr := ethutil.BigD(receiver.Address()) | ||||||
| 			tx.addLog(vm.Log{sender.Address(), [][]byte{addr.Add(addr, ethutil.Big1).Bytes()}, nil}) | 			self.state.AddLog(ethstate.Log{sender.Address(), [][]byte{ethutil.U256(addr.Add(addr, ethutil.Big1)).Bytes()}, nil}) | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
|   | |||||||
| @@ -8,7 +8,6 @@ import ( | |||||||
| 	"github.com/ethereum/go-ethereum/ethcrypto" | 	"github.com/ethereum/go-ethereum/ethcrypto" | ||||||
| 	"github.com/ethereum/go-ethereum/ethstate" | 	"github.com/ethereum/go-ethereum/ethstate" | ||||||
| 	"github.com/ethereum/go-ethereum/ethutil" | 	"github.com/ethereum/go-ethereum/ethutil" | ||||||
| 	"github.com/ethereum/go-ethereum/vm" |  | ||||||
| 	"github.com/obscuren/secp256k1-go" | 	"github.com/obscuren/secp256k1-go" | ||||||
| ) | ) | ||||||
|  |  | ||||||
| @@ -29,8 +28,6 @@ type Transaction struct { | |||||||
| 	v         byte | 	v         byte | ||||||
| 	r, s      []byte | 	r, s      []byte | ||||||
|  |  | ||||||
| 	logs []vm.Log |  | ||||||
|  |  | ||||||
| 	// Indicates whether this tx is a contract creation transaction | 	// Indicates whether this tx is a contract creation transaction | ||||||
| 	contractCreation bool | 	contractCreation bool | ||||||
| } | } | ||||||
| @@ -57,10 +54,6 @@ func NewTransactionFromValue(val *ethutil.Value) *Transaction { | |||||||
| 	return tx | 	return tx | ||||||
| } | } | ||||||
|  |  | ||||||
| func (self *Transaction) addLog(log vm.Log) { |  | ||||||
| 	self.logs = append(self.logs, log) |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func (self *Transaction) GasValue() *big.Int { | func (self *Transaction) GasValue() *big.Int { | ||||||
| 	return new(big.Int).Mul(self.Gas, self.GasPrice) | 	return new(big.Int).Mul(self.Gas, self.GasPrice) | ||||||
| } | } | ||||||
| @@ -212,7 +205,7 @@ type Receipt struct { | |||||||
| 	PostState         []byte | 	PostState         []byte | ||||||
| 	CumulativeGasUsed *big.Int | 	CumulativeGasUsed *big.Int | ||||||
| 	Bloom             []byte | 	Bloom             []byte | ||||||
| 	Logs              vm.Logs | 	logs              ethstate.Logs | ||||||
| } | } | ||||||
|  |  | ||||||
| func NewRecieptFromValue(val *ethutil.Value) *Receipt { | func NewRecieptFromValue(val *ethutil.Value) *Receipt { | ||||||
| @@ -229,12 +222,12 @@ func (self *Receipt) RlpValueDecode(decoder *ethutil.Value) { | |||||||
|  |  | ||||||
| 	it := decoder.Get(3).NewIterator() | 	it := decoder.Get(3).NewIterator() | ||||||
| 	for it.Next() { | 	for it.Next() { | ||||||
| 		self.Logs = append(self.Logs, vm.NewLogFromValue(it.Value())) | 		self.logs = append(self.logs, ethstate.NewLogFromValue(it.Value())) | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
|  |  | ||||||
| func (self *Receipt) RlpData() interface{} { | func (self *Receipt) RlpData() interface{} { | ||||||
| 	return []interface{}{self.PostState, self.CumulativeGasUsed, self.Bloom, self.Logs.RlpData()} | 	return []interface{}{self.PostState, self.CumulativeGasUsed, self.Bloom, self.logs.RlpData()} | ||||||
| } | } | ||||||
|  |  | ||||||
| func (self *Receipt) RlpEncode() []byte { | func (self *Receipt) RlpEncode() []byte { | ||||||
|   | |||||||
| @@ -31,8 +31,8 @@ func (self *VMEnv) BlockHash() []byte      { return self.block.Hash() } | |||||||
| func (self *VMEnv) Value() *big.Int        { return self.tx.Value } | func (self *VMEnv) Value() *big.Int        { return self.tx.Value } | ||||||
| func (self *VMEnv) State() *ethstate.State { return self.state } | func (self *VMEnv) State() *ethstate.State { return self.state } | ||||||
| func (self *VMEnv) GasLimit() *big.Int     { return self.block.GasLimit } | func (self *VMEnv) GasLimit() *big.Int     { return self.block.GasLimit } | ||||||
| func (self *VMEnv) AddLog(log vm.Log) { | func (self *VMEnv) AddLog(log ethstate.Log) { | ||||||
| 	self.tx.addLog(log) | 	self.state.AddLog(log) | ||||||
| } | } | ||||||
| func (self *VMEnv) Transfer(from, to vm.Account, amount *big.Int) error { | func (self *VMEnv) Transfer(from, to vm.Account, amount *big.Int) error { | ||||||
| 	return vm.Transfer(from, to, amount) | 	return vm.Transfer(from, to, amount) | ||||||
|   | |||||||
| @@ -185,8 +185,8 @@ func (self *Miner) mineNewBlock() { | |||||||
| 	self.ethereum.TxPool().RemoveSet(erroneous) | 	self.ethereum.TxPool().RemoveSet(erroneous) | ||||||
| 	self.txs = append(txs, unhandledTxs...) | 	self.txs = append(txs, unhandledTxs...) | ||||||
|  |  | ||||||
| 	self.block.SetReceipts(receipts) |  | ||||||
| 	self.block.SetTransactions(txs) | 	self.block.SetTransactions(txs) | ||||||
|  | 	self.block.SetReceipts(receipts) | ||||||
|  |  | ||||||
| 	// Accumulate the rewards included for this block | 	// Accumulate the rewards included for this block | ||||||
| 	stateManager.AccumelateRewards(self.block.State(), self.block, parent) | 	stateManager.AccumelateRewards(self.block.State(), self.block, parent) | ||||||
|   | |||||||
| @@ -34,7 +34,7 @@ func (self *VMEnv) BlockHash() []byte      { return self.block.Hash() } | |||||||
| func (self *VMEnv) Value() *big.Int        { return self.value } | func (self *VMEnv) Value() *big.Int        { return self.value } | ||||||
| func (self *VMEnv) State() *ethstate.State { return self.state } | func (self *VMEnv) State() *ethstate.State { return self.state } | ||||||
| func (self *VMEnv) GasLimit() *big.Int     { return self.block.GasLimit } | func (self *VMEnv) GasLimit() *big.Int     { return self.block.GasLimit } | ||||||
| func (self *VMEnv) AddLog(vm.Log)          {} | func (self *VMEnv) AddLog(ethstate.Log)    {} | ||||||
| func (self *VMEnv) Transfer(from, to vm.Account, amount *big.Int) error { | func (self *VMEnv) Transfer(from, to vm.Account, amount *big.Int) error { | ||||||
| 	return vm.Transfer(from, to, amount) | 	return vm.Transfer(from, to, amount) | ||||||
| } | } | ||||||
|   | |||||||
| @@ -1,4 +1,4 @@ | |||||||
| package vm | package ethstate | ||||||
| 
 | 
 | ||||||
| import "github.com/ethereum/go-ethereum/ethutil" | import "github.com/ethereum/go-ethereum/ethutil" | ||||||
| 
 | 
 | ||||||
| @@ -24,6 +24,8 @@ type State struct { | |||||||
| 	manifest *Manifest | 	manifest *Manifest | ||||||
|  |  | ||||||
| 	refund map[string]*big.Int | 	refund map[string]*big.Int | ||||||
|  |  | ||||||
|  | 	logs Logs | ||||||
| } | } | ||||||
|  |  | ||||||
| // Create a new state from a given trie | // Create a new state from a given trie | ||||||
| @@ -31,6 +33,18 @@ func New(trie *ethtrie.Trie) *State { | |||||||
| 	return &State{Trie: trie, stateObjects: make(map[string]*StateObject), manifest: NewManifest(), refund: make(map[string]*big.Int)} | 	return &State{Trie: trie, stateObjects: make(map[string]*StateObject), manifest: NewManifest(), refund: make(map[string]*big.Int)} | ||||||
| } | } | ||||||
|  |  | ||||||
|  | func (self *State) EmptyLogs() { | ||||||
|  | 	self.logs = nil | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func (self *State) AddLog(log Log) { | ||||||
|  | 	self.logs = append(self.logs, log) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func (self *State) Logs() Logs { | ||||||
|  | 	return self.logs | ||||||
|  | } | ||||||
|  |  | ||||||
| // Retrieve the balance from the given address or 0 if object not found | // Retrieve the balance from the given address or 0 if object not found | ||||||
| func (self *State) GetBalance(addr []byte) *big.Int { | func (self *State) GetBalance(addr []byte) *big.Int { | ||||||
| 	stateObject := self.GetStateObject(addr) | 	stateObject := self.GetStateObject(addr) | ||||||
| @@ -202,6 +216,10 @@ func (self *State) Copy() *State { | |||||||
| 			state.refund[addr] = refund | 			state.refund[addr] = refund | ||||||
| 		} | 		} | ||||||
|  |  | ||||||
|  | 		logs := make(Logs, len(self.logs)) | ||||||
|  | 		copy(logs, self.logs) | ||||||
|  | 		state.logs = logs | ||||||
|  |  | ||||||
| 		return state | 		return state | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| @@ -216,6 +234,7 @@ func (self *State) Set(state *State) { | |||||||
| 	self.Trie = state.Trie | 	self.Trie = state.Trie | ||||||
| 	self.stateObjects = state.stateObjects | 	self.stateObjects = state.stateObjects | ||||||
| 	self.refund = state.refund | 	self.refund = state.refund | ||||||
|  | 	self.logs = state.logs | ||||||
| } | } | ||||||
|  |  | ||||||
| func (s *State) Root() interface{} { | func (s *State) Root() interface{} { | ||||||
|   | |||||||
| @@ -35,7 +35,7 @@ func (self *VMEnv) BlockHash() []byte      { return self.block.Hash() } | |||||||
| func (self *VMEnv) Value() *big.Int        { return self.value } | func (self *VMEnv) Value() *big.Int        { return self.value } | ||||||
| func (self *VMEnv) State() *ethstate.State { return self.state } | func (self *VMEnv) State() *ethstate.State { return self.state } | ||||||
| func (self *VMEnv) GasLimit() *big.Int     { return self.block.GasLimit } | func (self *VMEnv) GasLimit() *big.Int     { return self.block.GasLimit } | ||||||
| func (self *VMEnv) AddLog(vm.Log)          {} | func (self *VMEnv) AddLog(ethstate.Log)    {} | ||||||
| func (self *VMEnv) Transfer(from, to vm.Account, amount *big.Int) error { | func (self *VMEnv) Transfer(from, to vm.Account, amount *big.Int) error { | ||||||
| 	return vm.Transfer(from, to, amount) | 	return vm.Transfer(from, to, amount) | ||||||
| } | } | ||||||
|   | |||||||
| @@ -20,7 +20,7 @@ type Environment interface { | |||||||
| 	BlockHash() []byte | 	BlockHash() []byte | ||||||
| 	GasLimit() *big.Int | 	GasLimit() *big.Int | ||||||
| 	Transfer(from, to Account, amount *big.Int) error | 	Transfer(from, to Account, amount *big.Int) error | ||||||
| 	AddLog(Log) | 	AddLog(ethstate.Log) | ||||||
| } | } | ||||||
|  |  | ||||||
| type Object interface { | type Object interface { | ||||||
| @@ -43,5 +43,9 @@ func Transfer(from, to Account, amount *big.Int) error { | |||||||
| 	from.SubBalance(amount) | 	from.SubBalance(amount) | ||||||
| 	to.AddBalance(amount) | 	to.AddBalance(amount) | ||||||
|  |  | ||||||
|  | 	// Add default LOG. Default = big(sender.addr) + 1 | ||||||
|  | 	//addr := ethutil.BigD(receiver.Address()) | ||||||
|  | 	//tx.addLog(vm.Log{sender.Address(), [][]byte{ethutil.U256(addr.Add(addr, ethutil.Big1)).Bytes()}, nil}) | ||||||
|  |  | ||||||
| 	return nil | 	return nil | ||||||
| } | } | ||||||
|   | |||||||
| @@ -5,6 +5,7 @@ import ( | |||||||
| 	"math/big" | 	"math/big" | ||||||
|  |  | ||||||
| 	"github.com/ethereum/go-ethereum/ethcrypto" | 	"github.com/ethereum/go-ethereum/ethcrypto" | ||||||
|  | 	"github.com/ethereum/go-ethereum/ethstate" | ||||||
| 	"github.com/ethereum/go-ethereum/ethutil" | 	"github.com/ethereum/go-ethereum/ethutil" | ||||||
| ) | ) | ||||||
|  |  | ||||||
| @@ -710,7 +711,7 @@ func (self *DebugVm) RunClosure(closure *Closure) (ret []byte, err error) { | |||||||
| 			for i := 0; i < n; i++ { | 			for i := 0; i < n; i++ { | ||||||
| 				topics[i] = stack.Pop().Bytes() | 				topics[i] = stack.Pop().Bytes() | ||||||
| 			} | 			} | ||||||
| 			self.env.AddLog(Log{closure.Address(), topics, data}) | 			self.env.AddLog(ethstate.Log{closure.Address(), topics, data}) | ||||||
| 		case MLOAD: | 		case MLOAD: | ||||||
| 			offset := stack.Pop() | 			offset := stack.Pop() | ||||||
| 			val := ethutil.BigD(mem.Get(offset.Int64(), 32)) | 			val := ethutil.BigD(mem.Get(offset.Int64(), 32)) | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user