mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-08-20 10:52:25 +00:00
Electrum fork
This commit is contained in:
parent
52f2461774
commit
2114e646f4
6 changed files with 382 additions and 97 deletions
|
|
@ -628,10 +628,10 @@ func accumulateRewards(config *params.ChainConfig, state *state.StateDB, header
|
|||
r.Sub(r, header.Number)
|
||||
r.Mul(r, blockReward)
|
||||
r.Div(r, big8)
|
||||
state.AddBalance(uncle.Coinbase, r)
|
||||
// state.AddBalance(uncle.Coinbase, r) // inflationary rewards removed by LydianElectrum
|
||||
|
||||
r.Div(blockReward, big32)
|
||||
reward.Add(reward, r)
|
||||
}
|
||||
state.AddBalance(header.Coinbase, reward)
|
||||
// state.AddBalance(header.Coinbase, reward) // inflationary rewards removed by LydianElectrum
|
||||
}
|
||||
|
|
|
|||
63
core/evm.go
63
core/evm.go
|
|
@ -18,6 +18,8 @@ package core
|
|||
|
||||
import (
|
||||
"math/big"
|
||||
"fmt"
|
||||
"encoding/hex"
|
||||
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"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
|
||||
func Transfer(db vm.StateDB, sender, recipient common.Address, amount *big.Int) {
|
||||
db.SubBalance(sender, amount)
|
||||
db.AddBalance(recipient, amount)
|
||||
// func Transfer(db vm.StateDB, sender, recipient common.Address, amount *big.Int) { // LydianElectrum requires knowledge of evm, not just evm.StateDB
|
||||
func Transfer(evm *vm.EVM, sender, recipient common.Address, amount *big.Int) {
|
||||
// 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)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -20,6 +20,7 @@ package state
|
|||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"encoding/hex"
|
||||
"math/big"
|
||||
"sort"
|
||||
"time"
|
||||
|
|
@ -67,8 +68,9 @@ type StateDB struct {
|
|||
trie Trie
|
||||
|
||||
// This map holds 'live' objects, which will get modified while processing a state transition.
|
||||
stateObjects map[common.Address]*stateObject
|
||||
stateObjectsDirty map[common.Address]struct{}
|
||||
stateObjects map[common.Address]*stateObject
|
||||
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.
|
||||
// State objects are used by the consensus core and VM which are
|
||||
|
|
@ -111,13 +113,14 @@ func New(root common.Hash, db Database) (*StateDB, error) {
|
|||
return nil, err
|
||||
}
|
||||
return &StateDB{
|
||||
db: db,
|
||||
trie: tr,
|
||||
stateObjects: make(map[common.Address]*stateObject),
|
||||
stateObjectsDirty: make(map[common.Address]struct{}),
|
||||
logs: make(map[common.Hash][]*types.Log),
|
||||
preimages: make(map[common.Hash][]byte),
|
||||
journal: newJournal(),
|
||||
db: db,
|
||||
trie: tr,
|
||||
stateObjects: make(map[common.Address]*stateObject),
|
||||
stateObjectsPending: make(map[common.Address]struct{}),
|
||||
stateObjectsDirty: make(map[common.Address]struct{}),
|
||||
logs: make(map[common.Hash][]*types.Log),
|
||||
preimages: make(map[common.Hash][]byte),
|
||||
journal: newJournal(),
|
||||
}, nil
|
||||
}
|
||||
|
||||
|
|
@ -141,6 +144,7 @@ func (self *StateDB) Reset(root common.Hash) error {
|
|||
}
|
||||
self.trie = tr
|
||||
self.stateObjects = make(map[common.Address]*stateObject)
|
||||
self.stateObjectsPending = make(map[common.Address]struct{})
|
||||
self.stateObjectsDirty = make(map[common.Address]struct{})
|
||||
self.thash = 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
|
||||
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 {
|
||||
fmt.Println("stateObject.Balance(): ", stateObject.Balance())
|
||||
return stateObject.Balance()
|
||||
}
|
||||
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 {
|
||||
|
|
@ -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.
|
||||
// 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.
|
||||
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
|
||||
if metrics.EnabledExpensive {
|
||||
defer func(start time.Time) { s.AccountUpdates += time.Since(start) }(time.Now())
|
||||
}
|
||||
// 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 {
|
||||
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.
|
||||
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
|
||||
if metrics.EnabledExpensive {
|
||||
defer func(start time.Time) { s.AccountUpdates += time.Since(start) }(time.Now())
|
||||
}
|
||||
// Delete the account from the trie
|
||||
stateObject.deleted = true
|
||||
|
||||
addr := stateObject.Address()
|
||||
addr := obj.Address()
|
||||
s.setError(s.trie.TryDelete(addr[:]))
|
||||
}
|
||||
|
||||
// Retrieve a state object given by the address. Returns nil if not found.
|
||||
func (s *StateDB) getStateObject(addr common.Address) (stateObject *stateObject) {
|
||||
// Prefer live objects
|
||||
// getStateObject retrieves a state object given by the address, returning nil if
|
||||
// the object is not found or was deleted in this execution context. If you need
|
||||
// to differentiate between non-existent/just-deleted, use getDeletedStateObject.
|
||||
func (s *StateDB) getStateObject(addr common.Address) *stateObject {
|
||||
if obj := s.getDeletedStateObject(addr); obj != nil && !obj.deleted {
|
||||
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 {
|
||||
if obj.deleted {
|
||||
return nil
|
||||
}
|
||||
return obj
|
||||
}
|
||||
// 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.
|
||||
func (self *StateDB) GetOrNewStateObject(addr common.Address) *stateObject {
|
||||
stateObject := self.getStateObject(addr)
|
||||
if stateObject == nil || stateObject.deleted {
|
||||
if stateObject == nil {
|
||||
stateObject, _ = self.createObject(addr)
|
||||
}
|
||||
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
|
||||
// the given address, it is overwritten and returned as the second return value.
|
||||
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.setNonce(0) // sets the object to dirty
|
||||
if prev == nil {
|
||||
|
|
@ -549,15 +604,16 @@ func (db *StateDB) ForEachStorage(addr common.Address, cb func(key, value common
|
|||
func (self *StateDB) Copy() *StateDB {
|
||||
// Copy all the basic fields, initialize the memory ones
|
||||
state := &StateDB{
|
||||
db: self.db,
|
||||
trie: self.db.CopyTrie(self.trie),
|
||||
stateObjects: make(map[common.Address]*stateObject, len(self.journal.dirties)),
|
||||
stateObjectsDirty: make(map[common.Address]struct{}, len(self.journal.dirties)),
|
||||
refund: self.refund,
|
||||
logs: make(map[common.Hash][]*types.Log, len(self.logs)),
|
||||
logSize: self.logSize,
|
||||
preimages: make(map[common.Hash][]byte, len(self.preimages)),
|
||||
journal: newJournal(),
|
||||
db: self.db,
|
||||
trie: self.db.CopyTrie(self.trie),
|
||||
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)),
|
||||
refund: self.refund,
|
||||
logs: make(map[common.Hash][]*types.Log, len(self.logs)),
|
||||
logSize: self.logSize,
|
||||
preimages: make(map[common.Hash][]byte, len(self.preimages)),
|
||||
journal: newJournal(),
|
||||
}
|
||||
// Copy the dirty states, logs, and preimages
|
||||
for addr := range self.journal.dirties {
|
||||
|
|
@ -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
|
||||
// nil
|
||||
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.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
|
||||
// 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
|
||||
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 {
|
||||
if _, exist := state.stateObjects[addr]; !exist {
|
||||
state.stateObjects[addr] = self.stateObjects[addr].deepCopy(state)
|
||||
state.stateObjectsDirty[addr] = struct{}{}
|
||||
}
|
||||
state.stateObjectsDirty[addr] = struct{}{}
|
||||
}
|
||||
for hash, logs := range self.logs {
|
||||
cpy := make([]*types.Log, len(logs))
|
||||
|
|
@ -622,11 +689,12 @@ func (self *StateDB) GetRefund() uint64 {
|
|||
return self.refund
|
||||
}
|
||||
|
||||
// Finalise finalises the state by removing the self destructed objects
|
||||
// and clears the journal as well as the refunds.
|
||||
// Finalise finalises the state by removing the self destructed objects and clears
|
||||
// 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) {
|
||||
for addr := range s.journal.dirties {
|
||||
stateObject, exist := s.stateObjects[addr]
|
||||
obj, exist := s.stateObjects[addr]
|
||||
if !exist {
|
||||
// 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
|
||||
|
|
@ -636,13 +704,12 @@ func (s *StateDB) Finalise(deleteEmptyObjects bool) {
|
|||
// Thus, we can safely ignore it here
|
||||
continue
|
||||
}
|
||||
|
||||
if stateObject.suicided || (deleteEmptyObjects && stateObject.empty()) {
|
||||
s.deleteStateObject(stateObject)
|
||||
if obj.suicided || (deleteEmptyObjects && obj.empty()) {
|
||||
obj.deleted = true
|
||||
} else {
|
||||
stateObject.updateRoot(s.db)
|
||||
s.updateStateObject(stateObject)
|
||||
obj.finalise()
|
||||
}
|
||||
s.stateObjectsPending[addr] = struct{}{}
|
||||
s.stateObjectsDirty[addr] = struct{}{}
|
||||
}
|
||||
// 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
|
||||
// goes into transaction receipts.
|
||||
func (s *StateDB) IntermediateRoot(deleteEmptyObjects bool) common.Hash {
|
||||
// Finalise all the dirty storage states and write them into the tries
|
||||
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
|
||||
if metrics.EnabledExpensive {
|
||||
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() {
|
||||
s.journal = newJournal()
|
||||
s.validRevisions = s.validRevisions[:0]
|
||||
s.refund = 0
|
||||
if len(s.journal.entries) > 0 {
|
||||
s.journal = newJournal()
|
||||
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.
|
||||
func (s *StateDB) Commit(deleteEmptyObjects bool) (root common.Hash, err error) {
|
||||
defer s.clearJournalAndRefund()
|
||||
func (s *StateDB) Commit(deleteEmptyObjects bool) (common.Hash, error) {
|
||||
// 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
|
||||
for addr, stateObject := range s.stateObjects {
|
||||
_, isDirty := s.stateObjectsDirty[addr]
|
||||
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:
|
||||
for addr := range s.stateObjectsDirty {
|
||||
if obj := s.stateObjects[addr]; !obj.deleted {
|
||||
// Write any contract code associated with the state object
|
||||
if stateObject.code != nil && stateObject.dirtyCode {
|
||||
s.db.TrieDB().InsertBlob(common.BytesToHash(stateObject.CodeHash()), stateObject.code)
|
||||
stateObject.dirtyCode = false
|
||||
if obj.code != nil && obj.dirtyCode {
|
||||
s.db.TrieDB().InsertBlob(common.BytesToHash(obj.CodeHash()), obj.code)
|
||||
obj.dirtyCode = false
|
||||
}
|
||||
// Write any storage changes in the state object to its storage trie.
|
||||
if err := stateObject.CommitTrie(s.db); err != nil {
|
||||
// Write any storage changes in the state object to its storage trie
|
||||
if err := obj.CommitTrie(s.db); err != nil {
|
||||
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
|
||||
if metrics.EnabledExpensive {
|
||||
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
|
||||
if err := rlp.DecodeBytes(leaf, &account); err != nil {
|
||||
return nil
|
||||
|
|
@ -724,5 +798,4 @@ func (s *StateDB) Commit(deleteEmptyObjects bool) (root common.Hash, err error)
|
|||
}
|
||||
return nil
|
||||
})
|
||||
return root, err
|
||||
}
|
||||
|
|
|
|||
|
|
@ -20,6 +20,8 @@ import (
|
|||
"errors"
|
||||
"math"
|
||||
"math/big"
|
||||
"fmt"
|
||||
"encoding/hex"
|
||||
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"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.
|
||||
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
|
||||
var gas uint64
|
||||
if contractCreation && homestead {
|
||||
if contractCreation && isEIP155 {
|
||||
gas = params.TxGasContractCreation
|
||||
} else {
|
||||
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
|
||||
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
|
||||
}
|
||||
gas += nz * params.TxDataNonZeroGas
|
||||
gas += nz * nonZeroGas
|
||||
|
||||
z := uint64(len(data)) - nz
|
||||
if (math.MaxUint64-gas)/params.TxDataZeroGas < z {
|
||||
|
|
@ -151,6 +157,14 @@ func (st *StateTransition) useGas(amount uint64) error {
|
|||
|
||||
func (st *StateTransition) buyGas() error {
|
||||
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 {
|
||||
return errInsufficientBalanceForGas
|
||||
}
|
||||
|
|
@ -160,7 +174,51 @@ func (st *StateTransition) buyGas() error {
|
|||
st.gas += 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
|
||||
}
|
||||
|
||||
|
|
@ -187,10 +245,11 @@ func (st *StateTransition) TransitionDb() (ret []byte, usedGas uint64, failed bo
|
|||
msg := st.msg
|
||||
sender := vm.AccountRef(msg.From())
|
||||
homestead := st.evm.ChainConfig().IsHomestead(st.evm.BlockNumber)
|
||||
istanbul := st.evm.ChainConfig().IsIstanbul(st.evm.BlockNumber)
|
||||
contractCreation := msg.To() == nil
|
||||
|
||||
// Pay intrinsic gas
|
||||
gas, err := IntrinsicGas(st.data, contractCreation, homestead)
|
||||
gas, err := IntrinsicGas(st.data, contractCreation, homestead, istanbul)
|
||||
if err != nil {
|
||||
return nil, 0, false, err
|
||||
}
|
||||
|
|
@ -222,7 +281,50 @@ func (st *StateTransition) TransitionDb() (ret []byte, usedGas uint64, failed bo
|
|||
}
|
||||
}
|
||||
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
|
||||
}
|
||||
|
|
@ -237,7 +339,50 @@ func (st *StateTransition) refundGas() {
|
|||
|
||||
// Return ETH for remaining gas, exchanged at the original rate.
|
||||
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
|
||||
// available for the next transaction.
|
||||
|
|
|
|||
|
|
@ -34,8 +34,9 @@ type (
|
|||
// CanTransferFunc is the signature of a transfer guard function
|
||||
CanTransferFunc func(StateDB, common.Address, *big.Int) bool
|
||||
// TransferFunc is the signature of a transfer function
|
||||
TransferFunc func(StateDB, common.Address, common.Address, *big.Int)
|
||||
// GetHashFunc returns the nth block hash in the blockchain
|
||||
// TransferFunc func(StateDB, common.Address, common.Address, *big.Int) // LydianElectrum: Transfer requieres the full vm object
|
||||
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.
|
||||
GetHashFunc func(uint64) common.Hash
|
||||
)
|
||||
|
|
@ -44,9 +45,12 @@ type (
|
|||
func run(evm *EVM, contract *Contract, input []byte, readOnly bool) ([]byte, error) {
|
||||
if contract.CodeAddr != nil {
|
||||
precompiles := PrecompiledContractsHomestead
|
||||
if evm.ChainConfig().IsByzantium(evm.BlockNumber) {
|
||||
if evm.chainRules.IsByzantium {
|
||||
precompiles = PrecompiledContractsByzantium
|
||||
}
|
||||
if evm.chainRules.IsIstanbul {
|
||||
precompiles = PrecompiledContractsIstanbul
|
||||
}
|
||||
if p := precompiles[*contract.CodeAddr]; p != nil {
|
||||
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) {
|
||||
precompiles := PrecompiledContractsHomestead
|
||||
if evm.ChainConfig().IsByzantium(evm.BlockNumber) {
|
||||
if evm.chainRules.IsByzantium {
|
||||
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
|
||||
if evm.vmConfig.Debug && evm.depth == 0 {
|
||||
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.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.
|
||||
// The contract is a scoped environment for this execution context only.
|
||||
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
|
||||
snapshot := evm.StateDB.Snapshot()
|
||||
evm.StateDB.CreateAccount(address)
|
||||
if evm.ChainConfig().IsEIP158(evm.BlockNumber) {
|
||||
if evm.chainRules.IsEIP158 {
|
||||
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.
|
||||
// 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)
|
||||
|
||||
// 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
|
||||
// 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
|
||||
|
|
@ -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
|
||||
// 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.
|
||||
if maxCodeSizeExceeded || (err != nil && (evm.ChainConfig().IsHomestead(evm.BlockNumber) || err != ErrCodeStoreOutOfGas)) {
|
||||
if maxCodeSizeExceeded || (err != nil && (evm.chainRules.IsHomestead || err != ErrCodeStoreOutOfGas)) {
|
||||
evm.StateDB.RevertToSnapshot(snapshot)
|
||||
if err != errExecutionReverted {
|
||||
contract.UseGas(contract.Gas)
|
||||
|
|
|
|||
|
|
@ -69,8 +69,6 @@ type Ethereum struct {
|
|||
// Channel for shutting down the service
|
||||
shutdownChan chan bool
|
||||
|
||||
server *p2p.Server
|
||||
|
||||
// Handlers
|
||||
txPool *core.TxPool
|
||||
blockchain *core.BlockChain
|
||||
|
|
@ -122,7 +120,9 @@ func New(ctx *node.ServiceContext, config *Config) (*Ethereum, error) {
|
|||
if !config.SyncMode.IsValid() {
|
||||
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)
|
||||
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 {
|
||||
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 {
|
||||
return nil, genesisErr
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue