From 52c6ccd2f063a6cccc35f5b4380b22fb9dd0f102 Mon Sep 17 00:00:00 2001
From: StephenButtolph <stephen@avalabs.org>
Date: Thu, 20 Aug 2020 09:42:06 -0400
Subject: implemented exportTx accept

---
 plugin/evm/block.go     | 78 ++++++++++++++++++++++++++-----------------------
 plugin/evm/export_tx.go | 35 ++++++++++++++++++++--
 plugin/evm/vm.go        | 13 +++++----
 3 files changed, 82 insertions(+), 44 deletions(-)

diff --git a/plugin/evm/block.go b/plugin/evm/block.go
index b3412a0..8e13c67 100644
--- a/plugin/evm/block.go
+++ b/plugin/evm/block.go
@@ -33,9 +33,12 @@ func (b *Block) Accept() error {
 	vm.updateStatus(b.ID(), choices.Accepted)
 
 	tx := vm.getAtomicTx(b.ethBlock)
+	if tx == nil {
+		return nil
+	}
 	utx, ok := tx.UnsignedTx.(UnsignedAtomicTx)
 	if !ok {
-		return errors.New("unknown atomic tx type")
+		return errors.New("unknown tx type")
 	}
 
 	return utx.Accept(vm.ctx, nil)
@@ -73,47 +76,50 @@ func (b *Block) Parent() snowman.Block {
 func (b *Block) Verify() error {
 	vm := b.vm
 	tx := vm.getAtomicTx(b.ethBlock)
-	switch atx := tx.UnsignedTx.(type) {
-	case *UnsignedImportTx:
-		if b.ethBlock.Hash() == vm.genesisHash {
-			return nil
-		}
-		p := b.Parent()
-		path := []*Block{}
-		inputs := new(ids.Set)
-		for {
-			if p.Status() == choices.Accepted || p.(*Block).ethBlock.Hash() == vm.genesisHash {
-				break
+	if tx != nil {
+		switch atx := tx.UnsignedTx.(type) {
+		case *UnsignedImportTx:
+			if b.ethBlock.Hash() == vm.genesisHash {
+				return nil
 			}
-			if ret, hit := vm.blockAtomicInputCache.Get(p.ID()); hit {
-				inputs = ret.(*ids.Set)
-				break
+			p := b.Parent()
+			path := []*Block{}
+			inputs := new(ids.Set)
+			for {
+				if p.Status() == choices.Accepted || p.(*Block).ethBlock.Hash() == vm.genesisHash {
+					break
+				}
+				if ret, hit := vm.blockAtomicInputCache.Get(p.ID()); hit {
+					inputs = ret.(*ids.Set)
+					break
+				}
+				path = append(path, p.(*Block))
+				p = p.Parent().(*Block)
 			}
-			path = append(path, p.(*Block))
-			p = p.Parent().(*Block)
-		}
-		for i := len(path) - 1; i >= 0; i-- {
-			inputsCopy := new(ids.Set)
-			p := path[i]
-			atx := vm.getAtomicTx(p.ethBlock)
-			inputs.Union(atx.UnsignedTx.(UnsignedAtomicTx).InputUTXOs())
-			inputsCopy.Union(*inputs)
-			vm.blockAtomicInputCache.Put(p.ID(), inputsCopy)
-		}
-		for _, in := range atx.InputUTXOs().List() {
-			if inputs.Contains(in) {
-				return errInvalidBlock
+			for i := len(path) - 1; i >= 0; i-- {
+				inputsCopy := new(ids.Set)
+				p := path[i]
+				atx := vm.getAtomicTx(p.ethBlock)
+				if atx != nil {
+					inputs.Union(atx.UnsignedTx.(UnsignedAtomicTx).InputUTXOs())
+					inputsCopy.Union(*inputs)
+				}
+				vm.blockAtomicInputCache.Put(p.ID(), inputsCopy)
 			}
+			for _, in := range atx.InputUTXOs().List() {
+				if inputs.Contains(in) {
+					return errInvalidBlock
+				}
+			}
+		case *UnsignedExportTx:
+		default:
+			return errors.New("unknown atomic tx type")
 		}
-	case *UnsignedExportTx:
-	default:
-		return errors.New("unknown atomic tx type")
-	}
 
-	if tx.UnsignedTx.(UnsignedAtomicTx).SemanticVerify(vm, tx) != nil {
-		return errInvalidBlock
+		if tx.UnsignedTx.(UnsignedAtomicTx).SemanticVerify(vm, tx) != nil {
+			return errInvalidBlock
+		}
 	}
-
 	_, err := b.vm.chain.InsertChain([]*types.Block{b.ethBlock})
 	return err
 }
diff --git a/plugin/evm/export_tx.go b/plugin/evm/export_tx.go
index 8b3c4f8..31b4681 100644
--- a/plugin/evm/export_tx.go
+++ b/plugin/evm/export_tx.go
@@ -10,6 +10,7 @@ import (
 	"github.com/ava-labs/coreth/core/state"
 	"github.com/ava-labs/go-ethereum/log"
 
+	"github.com/ava-labs/gecko/chains/atomic"
 	"github.com/ava-labs/gecko/database"
 	"github.com/ava-labs/gecko/ids"
 	"github.com/ava-labs/gecko/snow"
@@ -126,9 +127,37 @@ func (tx *UnsignedExportTx) SemanticVerify(
 }
 
 // Accept this transaction.
-func (tx *UnsignedExportTx) Accept(ctx *snow.Context, batch database.Batch) error {
-	// TODO: finish this function via gRPC
-	return nil
+func (tx *UnsignedExportTx) Accept(ctx *snow.Context, _ database.Batch) error {
+	txID := tx.ID()
+
+	elems := make([]*atomic.Element, len(tx.ExportedOutputs))
+	for i, out := range tx.ExportedOutputs {
+		utxo := &avax.UTXO{
+			UTXOID: avax.UTXOID{
+				TxID:        txID,
+				OutputIndex: uint32(i),
+			},
+			Asset: avax.Asset{ID: out.AssetID()},
+			Out:   out.Out,
+		}
+
+		utxoBytes, err := Codec.Marshal(utxo)
+		if err != nil {
+			return err
+		}
+
+		elem := &atomic.Element{
+			Key:   utxo.InputID().Bytes(),
+			Value: utxoBytes,
+		}
+		if out, ok := utxo.Out.(avax.Addressable); ok {
+			elem.Traits = out.Addresses()
+		}
+
+		elems[i] = elem
+	}
+
+	return ctx.SharedMemory.Put(tx.DestinationChain, elems)
 }
 
 // Create a new transaction
diff --git a/plugin/evm/vm.go b/plugin/evm/vm.go
index 0910f6d..4ea3793 100644
--- a/plugin/evm/vm.go
+++ b/plugin/evm/vm.go
@@ -177,11 +177,10 @@ type VM struct {
 }
 
 func (vm *VM) getAtomicTx(block *types.Block) *Tx {
+	extdata := block.ExtraData()
 	atx := new(Tx)
-	if extdata := block.ExtraData(); extdata != nil {
-		if err := vm.codec.Unmarshal(extdata, atx); err != nil {
-			panic(err)
-		}
+	if err := vm.codec.Unmarshal(extdata, atx); err != nil {
+		return nil
 	}
 	atx.Sign(vm.codec, nil)
 	return atx
@@ -284,7 +283,11 @@ func (vm *VM) Initialize(
 		return vm.getLastAccepted().ethBlock
 	})
 	chain.SetOnExtraStateChange(func(block *types.Block, state *state.StateDB) error {
-		return vm.getAtomicTx(block).UnsignedTx.(UnsignedAtomicTx).EVMStateTransfer(state)
+		tx := vm.getAtomicTx(block)
+		if tx == nil {
+			return nil
+		}
+		return tx.UnsignedTx.(UnsignedAtomicTx).EVMStateTransfer(state)
 	})
 	vm.blockCache = cache.LRU{Size: 2048}
 	vm.blockStatusCache = cache.LRU{Size: 1024}
-- 
cgit v1.2.3-70-g09d2