Electrum fork

This commit is contained in:
Juan Perez 2019-11-14 18:15:50 +01:00
parent 52f2461774
commit 2114e646f4
6 changed files with 382 additions and 97 deletions

View file

@ -628,10 +628,10 @@ func accumulateRewards(config *params.ChainConfig, state *state.StateDB, header
r.Sub(r, header.Number) r.Sub(r, header.Number)
r.Mul(r, blockReward) r.Mul(r, blockReward)
r.Div(r, big8) r.Div(r, big8)
state.AddBalance(uncle.Coinbase, r) // state.AddBalance(uncle.Coinbase, r) // inflationary rewards removed by LydianElectrum
r.Div(blockReward, big32) r.Div(blockReward, big32)
reward.Add(reward, r) reward.Add(reward, r)
} }
state.AddBalance(header.Coinbase, reward) // state.AddBalance(header.Coinbase, reward) // inflationary rewards removed by LydianElectrum
} }

View file

@ -18,6 +18,8 @@ package core
import ( import (
"math/big" "math/big"
"fmt"
"encoding/hex"
"github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/consensus" "github.com/ethereum/go-ethereum/consensus"
@ -91,7 +93,62 @@ func CanTransfer(db vm.StateDB, addr common.Address, amount *big.Int) bool {
} }
// Transfer subtracts amount from sender and adds amount to recipient using the given Db // Transfer subtracts amount from sender and adds amount to recipient using the given Db
func Transfer(db vm.StateDB, sender, recipient common.Address, amount *big.Int) { // func Transfer(db vm.StateDB, sender, recipient common.Address, amount *big.Int) { // LydianElectrum requires knowledge of evm, not just evm.StateDB
db.SubBalance(sender, amount) func Transfer(evm *vm.EVM, sender, recipient common.Address, amount *big.Int) {
db.AddBalance(recipient, amount) // db.SubBalance(sender, amount) // LydianElectrum
// evm.StateDB.SubBalance(sender, amount) // LydianElectrum: an ERC-20 transfer overrides this operation
// db.AddBalance(recipient, amount) // LydianElectrum
// evm.StateDB.AddBalance(recipient, amount) // LydianElectrum: an ERC-20 transfer overrides this operation
// LydianElectrum: CryptoEuro is an ERC-20 SC deployed on bootstrapping. Being the first one deployed, its address becomes predictable
address := common.HexToAddress("0x88e726de6cbadc47159c6ccd4f7868ae7a037730") // LydianElectrum: CriptoEuro contract hardcoded address
contract := vm.AccountRef(address)
// caller := vm.AccountRef(sender)
// methodHash := "a9059cbb" // transfer method
// methodHash := "9063e860" // transferOrigin method
methodHash := "222f5be0" // transferInternal method
// addressTo := "ca35b7d915458ef540ade6068dfe2f44e8fa733c" // con o sin left padding de leading zeros
addressTo := recipient.String()[2:] // removing leading 0x
addressSender := sender.String()[2:] // removing leading 0x
// padding del addressTo
for len(addressTo) < 64 { addressTo = "0" + addressTo }
// padding del addressSender
for len(addressSender) < 64 { addressSender = "0" + addressSender }
// convertimos la cantidad a hexadecimal
amountStr := fmt.Sprintf("%x", amount)
// padding
for len(amountStr) < 64 {
amountStr = "0" + amountStr
}
// juntamos todo en una cadena hexadecimal (SIN el 0x delante)
// inputDataHex := methodHash + addressTo + amountStr
inputDataHex := methodHash + addressSender + addressTo + amountStr
fmt.Println("inputDataHex: ", inputDataHex)
// lo convertimos de hexadecimal a []byte que es lo que necesitamos
inputData, err := hex.DecodeString(inputDataHex)
gas := uint64(3000000)
value := new(big.Int)
fmt.Println("sender: ", sender)
fmt.Println("senderString: ", sender.String())
fmt.Println("addressSender: ", addressSender)
fmt.Println("addressTo: ", addressTo)
fmt.Println("amountStr: ", amountStr)
fmt.Println("address: ", address)
// LydianElectrum: this is the ERC-20 transfer that overrides native coin operations
ret, returnGas, err := evm.CallCode(contract, address, inputData, gas, value)
fmt.Println("ret: ", ret)
fmt.Println("returnGas: ", returnGas)
fmt.Println("err: ", err)
} }

View file

@ -20,6 +20,7 @@ package state
import ( import (
"errors" "errors"
"fmt" "fmt"
"encoding/hex"
"math/big" "math/big"
"sort" "sort"
"time" "time"
@ -68,7 +69,8 @@ type StateDB struct {
// This map holds 'live' objects, which will get modified while processing a state transition. // This map holds 'live' objects, which will get modified while processing a state transition.
stateObjects map[common.Address]*stateObject stateObjects map[common.Address]*stateObject
stateObjectsDirty map[common.Address]struct{} stateObjectsPending map[common.Address]struct{} // State objects finalized but not yet written to the trie
stateObjectsDirty map[common.Address]struct{} // State objects modified in the current execution
// DB error. // DB error.
// State objects are used by the consensus core and VM which are // State objects are used by the consensus core and VM which are
@ -114,6 +116,7 @@ func New(root common.Hash, db Database) (*StateDB, error) {
db: db, db: db,
trie: tr, trie: tr,
stateObjects: make(map[common.Address]*stateObject), stateObjects: make(map[common.Address]*stateObject),
stateObjectsPending: make(map[common.Address]struct{}),
stateObjectsDirty: make(map[common.Address]struct{}), stateObjectsDirty: make(map[common.Address]struct{}),
logs: make(map[common.Hash][]*types.Log), logs: make(map[common.Hash][]*types.Log),
preimages: make(map[common.Hash][]byte), preimages: make(map[common.Hash][]byte),
@ -141,6 +144,7 @@ func (self *StateDB) Reset(root common.Hash) error {
} }
self.trie = tr self.trie = tr
self.stateObjects = make(map[common.Address]*stateObject) self.stateObjects = make(map[common.Address]*stateObject)
self.stateObjectsPending = make(map[common.Address]struct{})
self.stateObjectsDirty = make(map[common.Address]struct{}) self.stateObjectsDirty = make(map[common.Address]struct{})
self.thash = common.Hash{} self.thash = common.Hash{}
self.bhash = common.Hash{} self.bhash = common.Hash{}
@ -221,11 +225,44 @@ func (self *StateDB) Empty(addr common.Address) bool {
// 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 *StateDB) GetBalance(addr common.Address) *big.Int { func (self *StateDB) GetBalance(addr common.Address) *big.Int {
stateObject := self.getStateObject(addr) // LydianElectrum: Instead of getting the account balance from the ledger, retrieve it from the CryptoEuro ERC-20 Smart Contract
// To query the contract while lacking an EVM reference, we go directly through contract storage
/* stateObject := self.getStateObject(addr)
if stateObject != nil { if stateObject != nil {
fmt.Println("stateObject.Balance(): ", stateObject.Balance())
return stateObject.Balance() return stateObject.Balance()
} }
return common.Big0 return common.Big0
*/
// Debug: stateObject
contractAddr := common.HexToAddress("0x88e726de6cbadc47159c6ccd4f7868ae7a037730") // LydianElectrum: CryptoEuro contract hardcoded
// contractStateObject := self.getStateObject(contractAddr)
// fmt.Println("contractStateObject: ", contractStateObject)
// Debug: contract storage
// Crunching hash index for contract token balance at address 0x8703f7b22fc5613497aee971e80480a46b226d3c // x must be replaced by 0
// key := "0000000000000000000000008703f7b22fc5613497aee971e80480a46b226d3c" // x must be replaced by 0
key := "000000000000000000000000" + hex.EncodeToString(addr.Bytes())
index := "0000000000000000000000000000000000000000000000000000000000000001"
decoded, err := hex.DecodeString(key + index) // No 0x padding for GoLang keccak256 implementation
if err != nil {
fmt.Println("err: ", err)
}
fmt.Println("decoded: ", hex.EncodeToString(decoded))
var newKey = crypto.Keccak256(decoded)
fmt.Println("newKey: ", hex.EncodeToString(newKey))
var h common.Hash
h.SetBytes(newKey)
getStateNewKey := self.GetState(contractAddr, h)
fmt.Println("getStateNewKey: ", getStateNewKey)
// Convert []byte into big.Int
z := getStateNewKey.Big()
fmt.Println("z: ", z)
return z
} }
func (self *StateDB) GetNonce(addr common.Address) uint64 { func (self *StateDB) GetNonce(addr common.Address) uint64 {
@ -386,6 +423,15 @@ func (self *StateDB) SetState(addr common.Address, key, value common.Hash) {
} }
} }
// SetStorage replaces the entire storage for the specified account with given
// storage. This function should only be used for debugging.
func (self *StateDB) SetStorage(addr common.Address, storage map[common.Hash]common.Hash) {
stateObject := self.GetOrNewStateObject(addr)
if stateObject != nil {
stateObject.SetStorage(storage)
}
}
// Suicide marks the given account as suicided. // Suicide marks the given account as suicided.
// This clears the account balance. // This clears the account balance.
// //
@ -412,15 +458,15 @@ func (self *StateDB) Suicide(addr common.Address) bool {
// //
// updateStateObject writes the given object to the trie. // updateStateObject writes the given object to the trie.
func (s *StateDB) updateStateObject(stateObject *stateObject) { func (s *StateDB) updateStateObject(obj *stateObject) {
// Track the amount of time wasted on updating the account from the trie // Track the amount of time wasted on updating the account from the trie
if metrics.EnabledExpensive { if metrics.EnabledExpensive {
defer func(start time.Time) { s.AccountUpdates += time.Since(start) }(time.Now()) defer func(start time.Time) { s.AccountUpdates += time.Since(start) }(time.Now())
} }
// Encode the account and update the account trie // Encode the account and update the account trie
addr := stateObject.Address() addr := obj.Address()
data, err := rlp.EncodeToBytes(stateObject) data, err := rlp.EncodeToBytes(obj)
if err != nil { if err != nil {
panic(fmt.Errorf("can't encode object at %x: %v", addr[:], err)) panic(fmt.Errorf("can't encode object at %x: %v", addr[:], err))
} }
@ -428,25 +474,33 @@ func (s *StateDB) updateStateObject(stateObject *stateObject) {
} }
// deleteStateObject removes the given object from the state trie. // deleteStateObject removes the given object from the state trie.
func (s *StateDB) deleteStateObject(stateObject *stateObject) { func (s *StateDB) deleteStateObject(obj *stateObject) {
// Track the amount of time wasted on deleting the account from the trie // Track the amount of time wasted on deleting the account from the trie
if metrics.EnabledExpensive { if metrics.EnabledExpensive {
defer func(start time.Time) { s.AccountUpdates += time.Since(start) }(time.Now()) defer func(start time.Time) { s.AccountUpdates += time.Since(start) }(time.Now())
} }
// Delete the account from the trie // Delete the account from the trie
stateObject.deleted = true addr := obj.Address()
addr := stateObject.Address()
s.setError(s.trie.TryDelete(addr[:])) s.setError(s.trie.TryDelete(addr[:]))
} }
// Retrieve a state object given by the address. Returns nil if not found. // getStateObject retrieves a state object given by the address, returning nil if
func (s *StateDB) getStateObject(addr common.Address) (stateObject *stateObject) { // the object is not found or was deleted in this execution context. If you need
// Prefer live objects // to differentiate between non-existent/just-deleted, use getDeletedStateObject.
if obj := s.stateObjects[addr]; obj != nil { func (s *StateDB) getStateObject(addr common.Address) *stateObject {
if obj.deleted { if obj := s.getDeletedStateObject(addr); obj != nil && !obj.deleted {
return nil return obj
} }
return nil
}
// getDeletedStateObject is similar to getStateObject, but instead of returning
// nil for a deleted state object, it returns the actual object with the deleted
// flag set. This is needed by the state journal to revert to the correct self-
// destructed object instead of wiping all knowledge about the state object.
func (s *StateDB) getDeletedStateObject(addr common.Address) *stateObject {
// Prefer live objects if any is available
if obj := s.stateObjects[addr]; obj != nil {
return obj return obj
} }
// Track the amount of time wasted on loading the object from the database // Track the amount of time wasted on loading the object from the database
@ -477,7 +531,7 @@ func (self *StateDB) setStateObject(object *stateObject) {
// Retrieve a state object or create a new state object if nil. // Retrieve a state object or create a new state object if nil.
func (self *StateDB) GetOrNewStateObject(addr common.Address) *stateObject { func (self *StateDB) GetOrNewStateObject(addr common.Address) *stateObject {
stateObject := self.getStateObject(addr) stateObject := self.getStateObject(addr)
if stateObject == nil || stateObject.deleted { if stateObject == nil {
stateObject, _ = self.createObject(addr) stateObject, _ = self.createObject(addr)
} }
return stateObject return stateObject
@ -486,7 +540,8 @@ func (self *StateDB) GetOrNewStateObject(addr common.Address) *stateObject {
// createObject creates a new state object. If there is an existing account with // createObject creates a new state object. If there is an existing account with
// the given address, it is overwritten and returned as the second return value. // the given address, it is overwritten and returned as the second return value.
func (self *StateDB) createObject(addr common.Address) (newobj, prev *stateObject) { func (self *StateDB) createObject(addr common.Address) (newobj, prev *stateObject) {
prev = self.getStateObject(addr) prev = self.getDeletedStateObject(addr) // Note, prev might have been deleted, we need that!
newobj = newObject(self, addr, Account{}) newobj = newObject(self, addr, Account{})
newobj.setNonce(0) // sets the object to dirty newobj.setNonce(0) // sets the object to dirty
if prev == nil { if prev == nil {
@ -552,6 +607,7 @@ func (self *StateDB) Copy() *StateDB {
db: self.db, db: self.db,
trie: self.db.CopyTrie(self.trie), trie: self.db.CopyTrie(self.trie),
stateObjects: make(map[common.Address]*stateObject, len(self.journal.dirties)), stateObjects: make(map[common.Address]*stateObject, len(self.journal.dirties)),
stateObjectsPending: make(map[common.Address]struct{}, len(self.stateObjectsPending)),
stateObjectsDirty: make(map[common.Address]struct{}, len(self.journal.dirties)), stateObjectsDirty: make(map[common.Address]struct{}, len(self.journal.dirties)),
refund: self.refund, refund: self.refund,
logs: make(map[common.Hash][]*types.Log, len(self.logs)), logs: make(map[common.Hash][]*types.Log, len(self.logs)),
@ -566,18 +622,29 @@ func (self *StateDB) Copy() *StateDB {
// in the stateObjects: OOG after touch on ripeMD prior to Byzantium. Thus, we need to check for // in the stateObjects: OOG after touch on ripeMD prior to Byzantium. Thus, we need to check for
// nil // nil
if object, exist := self.stateObjects[addr]; exist { if object, exist := self.stateObjects[addr]; exist {
// Even though the original object is dirty, we are not copying the journal,
// so we need to make sure that anyside effect the journal would have caused
// during a commit (or similar op) is already applied to the copy.
state.stateObjects[addr] = object.deepCopy(state) state.stateObjects[addr] = object.deepCopy(state)
state.stateObjectsDirty[addr] = struct{}{}
state.stateObjectsDirty[addr] = struct{}{} // Mark the copy dirty to force internal (code/state) commits
state.stateObjectsPending[addr] = struct{}{} // Mark the copy pending to force external (account) commits
} }
} }
// Above, we don't copy the actual journal. This means that if the copy is copied, the // Above, we don't copy the actual journal. This means that if the copy is copied, the
// loop above will be a no-op, since the copy's journal is empty. // loop above will be a no-op, since the copy's journal is empty.
// Thus, here we iterate over stateObjects, to enable copies of copies // Thus, here we iterate over stateObjects, to enable copies of copies
for addr := range self.stateObjectsPending {
if _, exist := state.stateObjects[addr]; !exist {
state.stateObjects[addr] = self.stateObjects[addr].deepCopy(state)
}
state.stateObjectsPending[addr] = struct{}{}
}
for addr := range self.stateObjectsDirty { for addr := range self.stateObjectsDirty {
if _, exist := state.stateObjects[addr]; !exist { if _, exist := state.stateObjects[addr]; !exist {
state.stateObjects[addr] = self.stateObjects[addr].deepCopy(state) state.stateObjects[addr] = self.stateObjects[addr].deepCopy(state)
state.stateObjectsDirty[addr] = struct{}{}
} }
state.stateObjectsDirty[addr] = struct{}{}
} }
for hash, logs := range self.logs { for hash, logs := range self.logs {
cpy := make([]*types.Log, len(logs)) cpy := make([]*types.Log, len(logs))
@ -622,11 +689,12 @@ func (self *StateDB) GetRefund() uint64 {
return self.refund return self.refund
} }
// Finalise finalises the state by removing the self destructed objects // Finalise finalises the state by removing the self destructed objects and clears
// and clears the journal as well as the refunds. // the journal as well as the refunds. Finalise, however, will not push any updates
// into the tries just yet. Only IntermediateRoot or Commit will do that.
func (s *StateDB) Finalise(deleteEmptyObjects bool) { func (s *StateDB) Finalise(deleteEmptyObjects bool) {
for addr := range s.journal.dirties { for addr := range s.journal.dirties {
stateObject, exist := s.stateObjects[addr] obj, exist := s.stateObjects[addr]
if !exist { if !exist {
// ripeMD is 'touched' at block 1714175, in tx 0x1237f737031e40bcde4a8b7e717b2d15e3ecadfe49bb1bbc71ee9deb09c6fcf2 // ripeMD is 'touched' at block 1714175, in tx 0x1237f737031e40bcde4a8b7e717b2d15e3ecadfe49bb1bbc71ee9deb09c6fcf2
// That tx goes out of gas, and although the notion of 'touched' does not exist there, the // That tx goes out of gas, and although the notion of 'touched' does not exist there, the
@ -636,13 +704,12 @@ func (s *StateDB) Finalise(deleteEmptyObjects bool) {
// Thus, we can safely ignore it here // Thus, we can safely ignore it here
continue continue
} }
if obj.suicided || (deleteEmptyObjects && obj.empty()) {
if stateObject.suicided || (deleteEmptyObjects && stateObject.empty()) { obj.deleted = true
s.deleteStateObject(stateObject)
} else { } else {
stateObject.updateRoot(s.db) obj.finalise()
s.updateStateObject(stateObject)
} }
s.stateObjectsPending[addr] = struct{}{}
s.stateObjectsDirty[addr] = struct{}{} s.stateObjectsDirty[addr] = struct{}{}
} }
// Invalidate journal because reverting across transactions is not allowed. // Invalidate journal because reverting across transactions is not allowed.
@ -653,8 +720,21 @@ func (s *StateDB) Finalise(deleteEmptyObjects bool) {
// It is called in between transactions to get the root hash that // It is called in between transactions to get the root hash that
// goes into transaction receipts. // goes into transaction receipts.
func (s *StateDB) IntermediateRoot(deleteEmptyObjects bool) common.Hash { func (s *StateDB) IntermediateRoot(deleteEmptyObjects bool) common.Hash {
// Finalise all the dirty storage states and write them into the tries
s.Finalise(deleteEmptyObjects) s.Finalise(deleteEmptyObjects)
for addr := range s.stateObjectsPending {
obj := s.stateObjects[addr]
if obj.deleted {
s.deleteStateObject(obj)
} else {
obj.updateRoot(s.db)
s.updateStateObject(obj)
}
}
if len(s.stateObjectsPending) > 0 {
s.stateObjectsPending = make(map[common.Address]struct{})
}
// Track the amount of time wasted on hashing the account trie // Track the amount of time wasted on hashing the account trie
if metrics.EnabledExpensive { if metrics.EnabledExpensive {
defer func(start time.Time) { s.AccountHashes += time.Since(start) }(time.Now()) defer func(start time.Time) { s.AccountHashes += time.Since(start) }(time.Now())
@ -671,46 +751,40 @@ func (self *StateDB) Prepare(thash, bhash common.Hash, ti int) {
} }
func (s *StateDB) clearJournalAndRefund() { func (s *StateDB) clearJournalAndRefund() {
if len(s.journal.entries) > 0 {
s.journal = newJournal() s.journal = newJournal()
s.validRevisions = s.validRevisions[:0]
s.refund = 0 s.refund = 0
}
s.validRevisions = s.validRevisions[:0] // Snapshots can be created without journal entires
} }
// Commit writes the state to the underlying in-memory trie database. // Commit writes the state to the underlying in-memory trie database.
func (s *StateDB) Commit(deleteEmptyObjects bool) (root common.Hash, err error) { func (s *StateDB) Commit(deleteEmptyObjects bool) (common.Hash, error) {
defer s.clearJournalAndRefund() // Finalize any pending changes and merge everything into the tries
s.IntermediateRoot(deleteEmptyObjects)
for addr := range s.journal.dirties {
s.stateObjectsDirty[addr] = struct{}{}
}
// Commit objects to the trie, measuring the elapsed time // Commit objects to the trie, measuring the elapsed time
for addr, stateObject := range s.stateObjects { for addr := range s.stateObjectsDirty {
_, isDirty := s.stateObjectsDirty[addr] if obj := s.stateObjects[addr]; !obj.deleted {
switch {
case stateObject.suicided || (isDirty && deleteEmptyObjects && stateObject.empty()):
// If the object has been removed, don't bother syncing it
// and just mark it for deletion in the trie.
s.deleteStateObject(stateObject)
case isDirty:
// Write any contract code associated with the state object // Write any contract code associated with the state object
if stateObject.code != nil && stateObject.dirtyCode { if obj.code != nil && obj.dirtyCode {
s.db.TrieDB().InsertBlob(common.BytesToHash(stateObject.CodeHash()), stateObject.code) s.db.TrieDB().InsertBlob(common.BytesToHash(obj.CodeHash()), obj.code)
stateObject.dirtyCode = false obj.dirtyCode = false
} }
// Write any storage changes in the state object to its storage trie. // Write any storage changes in the state object to its storage trie
if err := stateObject.CommitTrie(s.db); err != nil { if err := obj.CommitTrie(s.db); err != nil {
return common.Hash{}, err return common.Hash{}, err
} }
// Update the object in the main account trie.
s.updateStateObject(stateObject)
} }
delete(s.stateObjectsDirty, addr) }
if len(s.stateObjectsDirty) > 0 {
s.stateObjectsDirty = make(map[common.Address]struct{})
} }
// Write the account trie changes, measuing the amount of wasted time // Write the account trie changes, measuing the amount of wasted time
if metrics.EnabledExpensive { if metrics.EnabledExpensive {
defer func(start time.Time) { s.AccountCommits += time.Since(start) }(time.Now()) defer func(start time.Time) { s.AccountCommits += time.Since(start) }(time.Now())
} }
root, err = s.trie.Commit(func(leaf []byte, parent common.Hash) error { return s.trie.Commit(func(leaf []byte, parent common.Hash) error {
var account Account var account Account
if err := rlp.DecodeBytes(leaf, &account); err != nil { if err := rlp.DecodeBytes(leaf, &account); err != nil {
return nil return nil
@ -724,5 +798,4 @@ func (s *StateDB) Commit(deleteEmptyObjects bool) (root common.Hash, err error)
} }
return nil return nil
}) })
return root, err
} }

View file

@ -20,6 +20,8 @@ import (
"errors" "errors"
"math" "math"
"math/big" "math/big"
"fmt"
"encoding/hex"
"github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/vm" "github.com/ethereum/go-ethereum/core/vm"
@ -76,10 +78,10 @@ type Message interface {
} }
// IntrinsicGas computes the 'intrinsic gas' for a message with the given data. // IntrinsicGas computes the 'intrinsic gas' for a message with the given data.
func IntrinsicGas(data []byte, contractCreation, homestead bool) (uint64, error) { func IntrinsicGas(data []byte, contractCreation, isEIP155 bool, isEIP2028 bool) (uint64, error) {
// Set the starting gas for the raw transaction // Set the starting gas for the raw transaction
var gas uint64 var gas uint64
if contractCreation && homestead { if contractCreation && isEIP155 {
gas = params.TxGasContractCreation gas = params.TxGasContractCreation
} else { } else {
gas = params.TxGas gas = params.TxGas
@ -94,10 +96,14 @@ func IntrinsicGas(data []byte, contractCreation, homestead bool) (uint64, error)
} }
} }
// Make sure we don't exceed uint64 for all data combinations // Make sure we don't exceed uint64 for all data combinations
if (math.MaxUint64-gas)/params.TxDataNonZeroGas < nz { nonZeroGas := params.TxDataNonZeroGasFrontier
if isEIP2028 {
nonZeroGas = params.TxDataNonZeroGasEIP2028
}
if (math.MaxUint64-gas)/nonZeroGas < nz {
return 0, vm.ErrOutOfGas return 0, vm.ErrOutOfGas
} }
gas += nz * params.TxDataNonZeroGas gas += nz * nonZeroGas
z := uint64(len(data)) - nz z := uint64(len(data)) - nz
if (math.MaxUint64-gas)/params.TxDataZeroGas < z { if (math.MaxUint64-gas)/params.TxDataZeroGas < z {
@ -151,6 +157,14 @@ func (st *StateTransition) useGas(amount uint64) error {
func (st *StateTransition) buyGas() error { func (st *StateTransition) buyGas() error {
mgval := new(big.Int).Mul(new(big.Int).SetUint64(st.msg.Gas()), st.gasPrice) mgval := new(big.Int).Mul(new(big.Int).SetUint64(st.msg.Gas()), st.gasPrice)
// Debug de st.msg.Gas()
fmt.Println("st.msg.Gas(): ", st.msg.Gas())
fmt.Println("st.gasPrice: ", st.gasPrice)
fmt.Println("mgval: ", mgval)
fmt.Println("st.msg.From(): ", st.msg.From())
fmt.Println("st.state.GetBalance(st.msg.From()): ", st.state.GetBalance(st.msg.From()))
if st.state.GetBalance(st.msg.From()).Cmp(mgval) < 0 { if st.state.GetBalance(st.msg.From()).Cmp(mgval) < 0 {
return errInsufficientBalanceForGas return errInsufficientBalanceForGas
} }
@ -160,7 +174,51 @@ func (st *StateTransition) buyGas() error {
st.gas += st.msg.Gas() st.gas += st.msg.Gas()
st.initialGas = st.msg.Gas() st.initialGas = st.msg.Gas()
st.state.SubBalance(st.msg.From(), mgval) // st.state.SubBalance(st.msg.From(), mgval) // LydianElectrum: Fee payment is override through token contract
address := common.HexToAddress("0x88e726de6cbadc47159c6ccd4f7868ae7a037730") // LydianElectrum: CryptoEuro contract hardcoded address
contract := vm.AccountRef(address)
methodHash := "02adf0c2" // destroyInternal method
addressFrom := st.msg.From().String()[2:] // removing leading 0x
// padding del addressFrom
for len(addressFrom) < 64 { addressFrom = "0" + addressFrom }
// convertimos la cantidad a hexadecimal
amountStr := fmt.Sprintf("%x", mgval)
// padding
for len(amountStr) < 64 {
amountStr = "0" + amountStr
}
// juntamos todo en una cadena hexadecimal (SIN el 0x delante)
inputDataHex := methodHash + addressFrom + amountStr
fmt.Println("destroyInternal inputDataHex: ", inputDataHex)
// lo convertimos de hexadecimal a []byte que es lo que necesitamos
inputData, errHex := hex.DecodeString(inputDataHex)
gas := uint64(3000000)
value := new(big.Int)
fmt.Println("destroyInternal addressFrom: ", addressFrom)
fmt.Println("destroyInternal amountStr: ", amountStr)
fmt.Println("destroyInternal address: ", address)
fmt.Println("destroyInternal st.msg.Gas(): ", st.msg.Gas())
fmt.Println("destroyInternal st.gasPrice: ", st.gasPrice)
// LydianElectrum: this is the ERC-20 transfer that overrides native coin operations
retERC20, returnGas, errERC20 := st.evm.CallCode(contract, address, inputData, gas, value)
fmt.Println("destroyInternal retERC20: ", retERC20)
fmt.Println("destroyInternal returnGas: ", returnGas)
fmt.Println("destroyInternal errERC20: ", errERC20)
fmt.Println("destroyInternal errHex: ", errHex)
return nil return nil
} }
@ -187,10 +245,11 @@ func (st *StateTransition) TransitionDb() (ret []byte, usedGas uint64, failed bo
msg := st.msg msg := st.msg
sender := vm.AccountRef(msg.From()) sender := vm.AccountRef(msg.From())
homestead := st.evm.ChainConfig().IsHomestead(st.evm.BlockNumber) homestead := st.evm.ChainConfig().IsHomestead(st.evm.BlockNumber)
istanbul := st.evm.ChainConfig().IsIstanbul(st.evm.BlockNumber)
contractCreation := msg.To() == nil contractCreation := msg.To() == nil
// Pay intrinsic gas // Pay intrinsic gas
gas, err := IntrinsicGas(st.data, contractCreation, homestead) gas, err := IntrinsicGas(st.data, contractCreation, homestead, istanbul)
if err != nil { if err != nil {
return nil, 0, false, err return nil, 0, false, err
} }
@ -222,7 +281,50 @@ func (st *StateTransition) TransitionDb() (ret []byte, usedGas uint64, failed bo
} }
} }
st.refundGas() st.refundGas()
st.state.AddBalance(st.evm.Coinbase, new(big.Int).Mul(new(big.Int).SetUint64(st.gasUsed()), st.gasPrice)) // st.state.AddBalance(st.evm.Coinbase, new(big.Int).Mul(new(big.Int).SetUint64(st.gasUsed()), st.gasPrice))
address := common.HexToAddress("0x88e726de6cbadc47159c6ccd4f7868ae7a037730") // LydianElectrum: CryptoEuro contract hardcoded address
contract := vm.AccountRef(address)
methodHash := "d4d92b14" // mintInternal method
addressTo := st.evm.Coinbase.String()[2:] // removing leading 0x
// padding del addressFrom
for len(addressTo) < 64 { addressTo = "0" + addressTo }
// convertimos la cantidad a hexadecimal
amountStr := fmt.Sprintf("%x", new(big.Int).Mul(new(big.Int).SetUint64(st.gasUsed()), st.gasPrice))
// padding
for len(amountStr) < 64 {
amountStr = "0" + amountStr
}
// juntamos todo en una cadena hexadecimal (SIN el 0x delante)
inputDataHex := methodHash + addressTo + amountStr
fmt.Println("mintInternal inputDataHex: ", inputDataHex)
// lo convertimos de hexadecimal a []byte que es lo que necesitamos
inputData, errHex := hex.DecodeString(inputDataHex)
gasERC20 := uint64(3000000)
value := new(big.Int)
fmt.Println("mintInternal addressTo: ", addressTo)
fmt.Println("mintInternal amountStr: ", amountStr)
fmt.Println("mintInternal address: ", address)
fmt.Println("mintInternal st.msg.Gas(): ", st.msg.Gas())
fmt.Println("mintInternal st.gasPrice: ", st.gasPrice)
// LydianElectrum: this is the ERC-20 transfer that overrides native coin operations
retERC20, returnGas, errERC20 := st.evm.CallCode(contract, address, inputData, gasERC20, value)
fmt.Println("mintInternal retERC20: ", retERC20)
fmt.Println("mintInternal returnGas: ", returnGas)
fmt.Println("mintInternal errERC20: ", errERC20)
fmt.Println("mintInternal errHex: ", errHex)
return ret, st.gasUsed(), vmerr != nil, err return ret, st.gasUsed(), vmerr != nil, err
} }
@ -237,7 +339,50 @@ func (st *StateTransition) refundGas() {
// Return ETH for remaining gas, exchanged at the original rate. // Return ETH for remaining gas, exchanged at the original rate.
remaining := new(big.Int).Mul(new(big.Int).SetUint64(st.gas), st.gasPrice) remaining := new(big.Int).Mul(new(big.Int).SetUint64(st.gas), st.gasPrice)
st.state.AddBalance(st.msg.From(), remaining) // st.state.AddBalance(st.msg.From(), remaining)
address := common.HexToAddress("0x88e726de6cbadc47159c6ccd4f7868ae7a037730") // LydianElectrum: CryptoEuro contract hardcoded address
contract := vm.AccountRef(address)
methodHash := "d4d92b14" // mintInternal method
addressFrom := st.msg.From().String()[2:] // removing leading 0x
// padding del addressFrom
for len(addressFrom) < 64 { addressFrom = "0" + addressFrom }
// convertimos la cantidad a hexadecimal
amountStr := fmt.Sprintf("%x", remaining)
// padding
for len(amountStr) < 64 {
amountStr = "0" + amountStr
}
// juntamos todo en una cadena hexadecimal (SIN el 0x delante)
inputDataHex := methodHash + addressFrom + amountStr
fmt.Println("mintInternal Refund inputDataHex: ", inputDataHex)
// lo convertimos de hexadecimal a []byte que es lo que necesitamos
inputData, errHex := hex.DecodeString(inputDataHex)
gas := uint64(3000000)
value := new(big.Int)
fmt.Println("mintInternal Refund addressFrom: ", addressFrom)
fmt.Println("mintInternal Refund amountStr: ", amountStr)
fmt.Println("mintInternal Refund address: ", address)
fmt.Println("mintInternal Refund st.msg.Gas(): ", st.msg.Gas())
fmt.Println("mintInternal Refund st.gasPrice: ", st.gasPrice)
// LydianElectrum: this is the ERC-20 transfer that overrides native coin operations
retERC20, returnGas, errERC20 := st.evm.CallCode(contract, address, inputData, gas, value)
fmt.Println("mintInternal Refund retERC20: ", retERC20)
fmt.Println("mintInternal Refund returnGas: ", returnGas)
fmt.Println("mintInternal Refund errERC20: ", errERC20)
fmt.Println("mintInternal Refund errHex: ", errHex)
// Also return remaining gas to the block gas counter so it is // Also return remaining gas to the block gas counter so it is
// available for the next transaction. // available for the next transaction.

View file

@ -34,8 +34,9 @@ type (
// CanTransferFunc is the signature of a transfer guard function // CanTransferFunc is the signature of a transfer guard function
CanTransferFunc func(StateDB, common.Address, *big.Int) bool CanTransferFunc func(StateDB, common.Address, *big.Int) bool
// TransferFunc is the signature of a transfer function // TransferFunc is the signature of a transfer function
TransferFunc func(StateDB, common.Address, common.Address, *big.Int) // TransferFunc func(StateDB, common.Address, common.Address, *big.Int) // LydianElectrum: Transfer requieres the full vm object
// GetHashFunc returns the nth block hash in the blockchain TransferFunc func(*EVM, common.Address, common.Address, *big.Int)
// GetHashFunc returns the n'th block hash in the blockchain
// and is used by the BLOCKHASH EVM op code. // and is used by the BLOCKHASH EVM op code.
GetHashFunc func(uint64) common.Hash GetHashFunc func(uint64) common.Hash
) )
@ -44,9 +45,12 @@ type (
func run(evm *EVM, contract *Contract, input []byte, readOnly bool) ([]byte, error) { func run(evm *EVM, contract *Contract, input []byte, readOnly bool) ([]byte, error) {
if contract.CodeAddr != nil { if contract.CodeAddr != nil {
precompiles := PrecompiledContractsHomestead precompiles := PrecompiledContractsHomestead
if evm.ChainConfig().IsByzantium(evm.BlockNumber) { if evm.chainRules.IsByzantium {
precompiles = PrecompiledContractsByzantium precompiles = PrecompiledContractsByzantium
} }
if evm.chainRules.IsIstanbul {
precompiles = PrecompiledContractsIstanbul
}
if p := precompiles[*contract.CodeAddr]; p != nil { if p := precompiles[*contract.CodeAddr]; p != nil {
return RunPrecompiledContract(p, input, contract) return RunPrecompiledContract(p, input, contract)
} }
@ -203,10 +207,13 @@ func (evm *EVM) Call(caller ContractRef, addr common.Address, input []byte, gas
) )
if !evm.StateDB.Exist(addr) { if !evm.StateDB.Exist(addr) {
precompiles := PrecompiledContractsHomestead precompiles := PrecompiledContractsHomestead
if evm.ChainConfig().IsByzantium(evm.BlockNumber) { if evm.chainRules.IsByzantium {
precompiles = PrecompiledContractsByzantium precompiles = PrecompiledContractsByzantium
} }
if precompiles[addr] == nil && evm.ChainConfig().IsEIP158(evm.BlockNumber) && value.Sign() == 0 { if evm.chainRules.IsIstanbul {
precompiles = PrecompiledContractsIstanbul
}
if precompiles[addr] == nil && evm.chainRules.IsEIP158 && value.Sign() == 0 {
// Calling a non existing account, don't do anything, but ping the tracer // Calling a non existing account, don't do anything, but ping the tracer
if evm.vmConfig.Debug && evm.depth == 0 { if evm.vmConfig.Debug && evm.depth == 0 {
evm.vmConfig.Tracer.CaptureStart(caller.Address(), addr, false, input, gas, value) evm.vmConfig.Tracer.CaptureStart(caller.Address(), addr, false, input, gas, value)
@ -216,7 +223,9 @@ func (evm *EVM) Call(caller ContractRef, addr common.Address, input []byte, gas
} }
evm.StateDB.CreateAccount(addr) evm.StateDB.CreateAccount(addr)
} }
evm.Transfer(evm.StateDB, caller.Address(), to.Address(), value) // evm.Transfer(evm.StateDB, caller.Address(), to.Address(), value) // LydianElectrum requires an evm reference to intercept native coin transfers
evm.Transfer(evm, caller.Address(), to.Address(), value)
// Initialise a new contract and set the code that is to be used by the EVM. // Initialise a new contract and set the code that is to be used by the EVM.
// The contract is a scoped environment for this execution context only. // The contract is a scoped environment for this execution context only.
contract := NewContract(caller, to, value, gas) contract := NewContract(caller, to, value, gas)
@ -394,10 +403,11 @@ func (evm *EVM) create(caller ContractRef, codeAndHash *codeAndHash, gas uint64,
// Create a new account on the state // Create a new account on the state
snapshot := evm.StateDB.Snapshot() snapshot := evm.StateDB.Snapshot()
evm.StateDB.CreateAccount(address) evm.StateDB.CreateAccount(address)
if evm.ChainConfig().IsEIP158(evm.BlockNumber) { if evm.chainRules.IsEIP158 {
evm.StateDB.SetNonce(address, 1) evm.StateDB.SetNonce(address, 1)
} }
evm.Transfer(evm.StateDB, caller.Address(), address, value) // evm.Transfer(evm.StateDB, caller.Address(), address, value) // LydianElectrum requires an evm reference to intercept native coin transfers
evm.Transfer(evm, caller.Address(), address, value)
// Initialise a new contract and set the code that is to be used by the EVM. // Initialise a new contract and set the code that is to be used by the EVM.
// The contract is a scoped environment for this execution context only. // The contract is a scoped environment for this execution context only.
@ -416,7 +426,7 @@ func (evm *EVM) create(caller ContractRef, codeAndHash *codeAndHash, gas uint64,
ret, err := run(evm, contract, nil, false) ret, err := run(evm, contract, nil, false)
// check whether the max code size has been exceeded // check whether the max code size has been exceeded
maxCodeSizeExceeded := evm.ChainConfig().IsEIP158(evm.BlockNumber) && len(ret) > params.MaxCodeSize maxCodeSizeExceeded := evm.chainRules.IsEIP158 && len(ret) > params.MaxCodeSize
// if the contract creation ran successfully and no errors were returned // if the contract creation ran successfully and no errors were returned
// calculate the gas required to store the code. If the code could not // calculate the gas required to store the code. If the code could not
// be stored due to not enough gas set an error and let it be handled // be stored due to not enough gas set an error and let it be handled
@ -433,7 +443,7 @@ func (evm *EVM) create(caller ContractRef, codeAndHash *codeAndHash, gas uint64,
// When an error was returned by the EVM or when setting the creation code // When an error was returned by the EVM or when setting the creation code
// above we revert to the snapshot and consume any gas remaining. Additionally // above we revert to the snapshot and consume any gas remaining. Additionally
// when we're in homestead this also counts for code storage gas errors. // when we're in homestead this also counts for code storage gas errors.
if maxCodeSizeExceeded || (err != nil && (evm.ChainConfig().IsHomestead(evm.BlockNumber) || err != ErrCodeStoreOutOfGas)) { if maxCodeSizeExceeded || (err != nil && (evm.chainRules.IsHomestead || err != ErrCodeStoreOutOfGas)) {
evm.StateDB.RevertToSnapshot(snapshot) evm.StateDB.RevertToSnapshot(snapshot)
if err != errExecutionReverted { if err != errExecutionReverted {
contract.UseGas(contract.Gas) contract.UseGas(contract.Gas)

View file

@ -69,8 +69,6 @@ type Ethereum struct {
// Channel for shutting down the service // Channel for shutting down the service
shutdownChan chan bool shutdownChan chan bool
server *p2p.Server
// Handlers // Handlers
txPool *core.TxPool txPool *core.TxPool
blockchain *core.BlockChain blockchain *core.BlockChain
@ -122,7 +120,9 @@ func New(ctx *node.ServiceContext, config *Config) (*Ethereum, error) {
if !config.SyncMode.IsValid() { if !config.SyncMode.IsValid() {
return nil, fmt.Errorf("invalid sync mode %d", config.SyncMode) return nil, fmt.Errorf("invalid sync mode %d", config.SyncMode)
} }
if config.Miner.GasPrice == nil || config.Miner.GasPrice.Cmp(common.Big0) <= 0 { // if config.Miner.GasPrice == nil || config.Miner.GasPrice.Cmp(common.Big0) <= 0 {
// LydianElectrum: Allowing miners to set gasPrice threshold to zero, in order to mine bootstrapping transactions
if config.Miner.GasPrice == nil || config.Miner.GasPrice.Cmp(common.Big0) < 0 {
log.Warn("Sanitizing invalid miner gas price", "provided", config.Miner.GasPrice, "updated", DefaultConfig.Miner.GasPrice) log.Warn("Sanitizing invalid miner gas price", "provided", config.Miner.GasPrice, "updated", DefaultConfig.Miner.GasPrice)
config.Miner.GasPrice = new(big.Int).Set(DefaultConfig.Miner.GasPrice) config.Miner.GasPrice = new(big.Int).Set(DefaultConfig.Miner.GasPrice)
} }
@ -137,7 +137,7 @@ func New(ctx *node.ServiceContext, config *Config) (*Ethereum, error) {
if err != nil { if err != nil {
return nil, err return nil, err
} }
chainConfig, genesisHash, genesisErr := core.SetupGenesisBlock(chainDb, config.Genesis) chainConfig, genesisHash, genesisErr := core.SetupGenesisBlockWithOverride(chainDb, config.Genesis, config.OverrideIstanbul)
if _, ok := genesisErr.(*params.ConfigCompatError); genesisErr != nil && !ok { if _, ok := genesisErr.(*params.ConfigCompatError); genesisErr != nil && !ok {
return nil, genesisErr return nil, genesisErr
} }