Skip to content
This repository has been archived by the owner on Apr 11, 2021. It is now read-only.

Integrated contracts-v2 #67

Merged
merged 30 commits into from
Nov 6, 2020
Merged

Integrated contracts-v2 #67

merged 30 commits into from
Nov 6, 2020

Conversation

smartcontracts
Copy link
Contributor

Description

Lots of changes, but the primary ones are:

  • Changing how we parse transactions to convert them to "ovm messages"
  • Updating state_manager.go with the new API
  • Updating our logging statements
  • Updating our state dump (I'd rather we pull this from somewhere external)

Contributing Agreement

return nil, 0, false, err
}

evm.Context.Origin = msg.From()
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hopefully this will be made unnecessary by a change @K-Ho is making to the OVM_ExecutionManager. Basically needed so I can get msg.sender == ovmStateManager.owner() to return true.

}
} else {
// OVM_ENABLED
st.buyGas()
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is the only part of the preCheck that we actually care about.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why is it safe to skip the nonce check?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It wasn't :-( I added the nonce check again.

if contractCreation {
// Here we are going to call the EM directly
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

All of this is now handled in toExecutionManagerRun, so not needed here anymore.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

awesome refactor


// If the tx fails we won't have incremented the nonce. In this case, increment it manually
log.Debug("Incrementing nonce due to transaction failure")
st.state.SetNonce(msg.From(), st.state.GetNonce(sender.Address())+1)
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We need to figure out the best way to handle this nonce eviction thing. @karlfloersch should we just go ahead and update the eviction logic?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Once we've stabilized Synthetix running in Contracts v2, and have deployed Mintr to this Geth & have it work, that seems to me to be the next highest priority

log.Debug("return data", "data", hexutil.Encode(ret))
if !vm.UsingOVM {
// OVM_DISABLED
st.state.AddBalance(st.evm.Coinbase, new(big.Int).Mul(new(big.Int).SetUint64(st.gasUsed()), st.gasPrice))
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No balances in the OVM.

}

if caller.Address() == OvmExecutionManager.Address &&
!strings.HasPrefix(strings.ToLower(addr.Hex()), "0xdeaddeaddeaddeaddeaddeaddeaddeaddead") &&
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

0xdead and 0x0000 addresses can't be the target.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why? What do these mean? Could we use a variable instead of hardcoded addrs?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

0xdead addresses are used for all of the OVM contracts that run in L2 (so the execution manager, state manager, etc.) Users aren't allowed to call these addresses via ovmCALLs & similar opcodes. We could probably use a variable but we need to coordinate this variable across everything.

if !UsingOVM {
// OVM_DISABLED
// Fail if we're trying to transfer more than the available balance
if !evm.Context.CanTransfer(evm.StateDB, caller.Address(), value) {
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Breaks things in the OVM (don't need it anyway).

core/vm/evm.go Outdated
if UsingOVM {
// OVM_ENABLED
if isTarget {
evm.OriginalTargetResult = ret[96:]
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ignore the first 96 bytes (the return status and ABI encoding parameters).

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is there any chance len(ret) < 96?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes -- fixed to address this.

@@ -124,6 +124,8 @@ func NewEVMInterpreter(evm *EVM, cfg Config) *EVMInterpreter {
}
}

var returnDataCopy string
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is the hack that bypasses an apparent bug

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Curious, what was the bug - also why do we need to do this manually? Isin.returnData not always set correctly?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a pretty crazy bug 😮

Has to do with internal Geth memory management... we gotta look into it further

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@gakonst unclear what the bug is. It appears that some combination of RETURNDATACOPY and other opcodes results in MSTORE overwriting in.returnData. Very strange.

@@ -806,7 +806,7 @@ func DoCall(ctx context.Context, b Backend, args CallArgs, blockNrOrHash rpc.Blo
}
}
// Set default gas & gas price if none were set
gas := uint64(math.MaxUint64 / 2)
gas := uint64(10000000)
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Will break with max gas because EM asserts that gas is < maxGasPerQueuePerEpoch (not sure what the right value is to put here -- block gas limit?)

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm using ExecutionManager.GetMaxTransactionGasLimit

var ZeroAddress = common.HexToAddress("0x0000000000000000000000000000000000000000")

type ovmTransaction struct {
Timestamp *big.Int "json:\"timestamp\""
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why the escaped "?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Took this from another part of geth where it used the escaped ".

}

// Signature type
data.WriteByte(byte(sigtype)) // 1 byte: 00 == EOACreate, 01 == EIP 155, 02 == ETH Sign Message
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've played with a few different styles of serialization, using bytes.Buffer, io.Writer and []byte. Curious if you have any preferences.

My favorite so far has been using []byte directly, see

func (c *CTCTxEIP155) Encode(b []byte) error {

}
}

func getQueueOrigin(
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm sorry about this

@@ -69,6 +88,7 @@ func run(evm *EVM, contract *Contract, input []byte, readOnly bool) ([]byte, err
return RunPrecompiledContract(p, input, contract)
}
}

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe no need to add extra whitelines for minimal diff?


OvmStateManager = OvmStateDump.Accounts["OVM_StateManager"]
OvmExecutionManager = OvmStateDump.Accounts["OVM_ExecutionManager"]
UsingOVM = os.Getenv("USING_OVM") == "true"
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Noted that this will be added to deploy config

Copy link
Contributor

@karlfloersch karlfloersch left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Got part of the way through & will finish shortly but so far it's looking great!


// If the tx fails we won't have incremented the nonce. In this case, increment it manually
log.Debug("Incrementing nonce due to transaction failure")
st.state.SetNonce(msg.From(), st.state.GetNonce(sender.Address())+1)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Once we've stabilized Synthetix running in Contracts v2, and have deployed Mintr to this Geth & have it work, that seems to me to be the next highest priority

@@ -326,6 +326,13 @@ func (tx *Transaction) AsMessage(s Signer) (Message, error) {

var err error
msg.from, err = Sender(s, tx)

if tx.meta.L1MessageSender != nil {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not entirely sure but I think it looks about right tbh.

Also, right here you should add:

if tx.meta.lastL1BlockNumber != nil {
  msg.l1BlockNumber = tx.meta.lastL1BlockNumber
}

Oh though I forgot -- we have to rename txId here - https://github.com/ethereum-optimism/go-ethereum/pull/67/files#diff-5500355cc4409489bee920d34f30a486e081409325cc12793ea7895fb64ac7daR605 to lastL1BlockNumber

func toExecutionManagerRun(evm *vm.EVM, msg Message) (Message, error) {
tx := ovmTransaction{
evm.Context.Time,
evm.Context.BlockNumber, // TODO (what's the correct block number?)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For an L1 to L2 transaction, is block.number supposed to be the L1 block number?

Yep

@karlfloersch @tynes what's the correct value for this?

Ah so we've got to set it in the same way you set the L1MessageSender from the meta. I wrote up how that works below

}

v, r, s := tx.RawSignatureValues()
v = big.NewInt(int64(v.Uint64() - 35 - 2*420))
Copy link
Contributor

@gakonst gakonst Nov 2, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
v = big.NewInt(int64(v.Uint64() - 35 - 2*420))
v = big.NewInt(int64(v.Uint64() - 35 - 2* CHAIN_ID))

Could refactor this out to a CHAIN_ID constant, maybe also add a comment that this is EIP-155?

core/state_transition.go Outdated Show resolved Hide resolved
}
} else {
// OVM_ENABLED
st.buyGas()
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why is it safe to skip the nonce check?

if contractCreation {
// Here we are going to call the EM directly
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

awesome refactor

Comment on lines +55 to +67
var isUnknown = true
for name, account := range OvmStateDump.Accounts {
if contract.Address() == account.Address {
isUnknown = false
abi := &(account.ABI)
method, err := abi.MethodById(input)
if err != nil {
log.Debug("Calling Known Contract", "Name", name, "ERROR", err)
} else {
log.Debug("Calling Known Contract", "Name", name, "Method", method.RawName)
}
}
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

OvmStateDump.Accounts is already a map, can't you just do account, ok := OvmStateDumpAccounts[name]?

Comment on lines +640 to +645
// ovmADDRESS will be set by the execution manager to the target address whenever it's
// about to create a new contract. This value is currently stored at the [15] storage slot.
// Can pull this specific storage slot to get the address that the execution manager is
// trying to create to, and create to it.
slot := common.HexToHash(strconv.FormatInt(15, 16))
contractAddr = common.BytesToAddress(evm.StateDB.GetState(OvmExecutionManager.Address, slot).Bytes())
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this referring to this? This is maybe a footgun in case the layout of the ExecutionManager changes, maybe consider adding a big big warning to this and the contracts?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also, consider refactoring the else branch to a helper function?

@@ -124,6 +124,8 @@ func NewEVMInterpreter(evm *EVM, cfg Config) *EVMInterpreter {
}
}

var returnDataCopy string
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Curious, what was the bug - also why do we need to do this manually? Isin.returnData not always set correctly?

@@ -859,7 +863,10 @@ func DoCall(ctx context.Context, b Backend, args CallArgs, blockNrOrHash rpc.Blo
// Setup the gas pool (also for unmetered requests)
// and apply the message.
gp := new(core.GasPool).AddGas(math.MaxUint64)
res, gas, failed, err := core.ApplyMessage(evm, msg, gp)
log.Debug(">>>>>> Serving an eth_call <<<<<<", "From", addr.Hex(), "To", args.To.Hex())
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
log.Debug(">>>>>> Serving an eth_call <<<<<<", "From", addr.Hex(), "To", args.To.Hex())

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Definitely should remove this logline, there will be tons of these

log.Debug(">>>>>> Serving an eth_call <<<<<<", "From", addr.Hex(), "To", args.To.Hex())
evm.Context.EthCallSender = &addr
res, gas, failed, err := core.ApplyMessage(evm, outmsg, gp)
log.Debug("<<<<<< Served an eth_call >>>>>>", "From", addr.Hex(), "To", args.To.Hex())
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
log.Debug("<<<<<< Served an eth_call >>>>>>", "From", addr.Hex(), "To", args.To.Hex())

(just a reminder to remove once done debugging)

@@ -266,6 +356,65 @@ func (evm *EVM) Call(caller ContractRef, addr common.Address, input []byte, gas
contract.UseGas(contract.Gas)
}
}

if UsingOVM {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What is the rationale behind the whole isTarget/OriginalTarget logic? What can go wrong here?


if vm.UsingOVM {
// OVM_ENABLED
log.Debug("<<<<<< Served an OVM transaction >>>>>>")
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't know if we need these loglines anymore, but it probably isn't a bad idea to log something along the lines of ovm enabled once at startup if the env var that turns on ovm is set

if err != nil {
return nil, err
}

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think we need to add extra newlines as it just creates a bigger diff from upstream. Go code generally has less newlines between blocks of code compared to JS based on reading a bunch of Go codebases 🤷


func getQueueOrigin(
queueOrigin *big.Int,
) (types.QueueOrigin, error) {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm confused about this because there should only be 2 queue origins?

@tynes
Copy link
Collaborator

tynes commented Nov 6, 2020

ethereum-optimism/optimism#358 must be merged at the same time


if len(address) == 0 {
log.Warn("No TX_INGESTION_SIGNER_ADDRESS supplied. Using ZERO_ADDRESS default.")
address = "0000000000000000000000000000000000000000"
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This always breaks in this code path because address len is 40

@tynes tynes merged commit 93c5a6a into master Nov 6, 2020
@tynes tynes deleted the dev/contracts-v2-v2 branch November 6, 2020 21:06
@tynes tynes restored the dev/contracts-v2-v2 branch November 6, 2020 21:06
karlfloersch added a commit that referenced this pull request Nov 20, 2020
* Works, but need to figure out this bug

* Remove unnecessary log statements

* Finalizing integration

* Small code cleanups

* Added a few more comments

* Various bugfixes

* Works, but need to figure out this bug

* Remove unnecessary log statements

* Finalizing integration

* Small code cleanups

* Added a few more comments

* Various bugfixes

* Added custom fillbytes function

* Removed old test file for now

* Fix linting errors

* Fix linting errors

* Reduce gas limit again

* Various fixes!

* Minor updates to get l1 ingestion address

* Fix remaining bugs

* Fix lint errors

* Fix broken tests. WARN I skipped some

* loglines: remove before deployment

* core: less diff by removing newlines

* core: less diff by removing newlines

* rollup: remove logline in signtx

* core/ovm: handle errors when type casting

* ovm: log applying message

Co-authored-by: Karl Floersch <karl@karlfloersch.com>
Co-authored-by: Mark Tyneway <mark.tyneway@gmail.com>
karlfloersch added a commit that referenced this pull request Nov 20, 2020
* Works, but need to figure out this bug

* Remove unnecessary log statements

* Finalizing integration

* Small code cleanups

* Added a few more comments

* Various bugfixes

* Works, but need to figure out this bug

* Remove unnecessary log statements

* Finalizing integration

* Small code cleanups

* Added a few more comments

* Various bugfixes

* Added custom fillbytes function

* Removed old test file for now

* Fix linting errors

* Fix linting errors

* Reduce gas limit again

* Various fixes!

* Minor updates to get l1 ingestion address

* Fix remaining bugs

* Fix lint errors

* Fix broken tests. WARN I skipped some

* loglines: remove before deployment

* core: less diff by removing newlines

* core: less diff by removing newlines

* rollup: remove logline in signtx

* core/ovm: handle errors when type casting

* ovm: log applying message

Co-authored-by: Karl Floersch <karl@karlfloersch.com>
Co-authored-by: Mark Tyneway <mark.tyneway@gmail.com>
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants