diff --git a/fvm/evm/handler/blockstore_test.go b/fvm/evm/handler/blockstore_test.go index 77720b143a2..b198f04c053 100644 --- a/fvm/evm/handler/blockstore_test.go +++ b/fvm/evm/handler/blockstore_test.go @@ -1,6 +1,7 @@ package handler_test import ( + "math/big" "testing" "github.com/stretchr/testify/require" @@ -32,7 +33,7 @@ func TestBlockStore(t *testing.T) { require.Equal(t, expectedParentHash, bp.ParentBlockHash) // commit block proposal - supply := uint64(100) + supply := big.NewInt(100) bp.TotalSupply = supply err = bs.CommitBlockProposal() require.NoError(t, err) diff --git a/fvm/evm/handler/handler.go b/fvm/evm/handler/handler.go index acbfc1c173e..8bb9d4e09aa 100644 --- a/fvm/evm/handler/handler.go +++ b/fvm/evm/handler/handler.go @@ -2,6 +2,7 @@ package handler import ( "bytes" + "math/big" gethTypes "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/rlp" @@ -14,14 +15,6 @@ import ( // ContractHandler is responsible for triggering calls to emulator, metering, // event emission and updating the block -// -// TODO and Warning: currently database keeps a copy of roothash, and if after -// commiting the changes by the evm we want to revert in this code we need to reset that -// or we should always do all the checks and return before calling the emulator, -// after that should be only event emissions and computation usage updates. -// thats another reason we first check the computation limit before using. -// in the future we might benefit from a view style of access to db passed as -// a param to the emulator. type ContractHandler struct { flowTokenAddress common.Address blockstore types.BlockStore @@ -199,7 +192,7 @@ func (a *Account) Deposit(v *types.FLOWTokenVault) { a.address, v.Balance().ToAttoFlow(), ) - a.executeAndHandleCall(a.fch.getBlockContext(), call, v.Balance().ToAttoFlow().Uint64(), false) + a.executeAndHandleCall(a.fch.getBlockContext(), call, v.Balance().ToAttoFlow(), false) } // Withdraw deducts the balance from the account and @@ -213,7 +206,8 @@ func (a *Account) Withdraw(b types.Balance) *types.FLOWTokenVault { // check balance of flex vault bp, err := a.fch.blockstore.BlockProposal() handleError(err) - if b.ToAttoFlow().Uint64() > bp.TotalSupply { + // b > total supply + if b.ToAttoFlow().Cmp(bp.TotalSupply) == 1 { handleError(types.ErrInsufficientTotalSupply) } @@ -221,7 +215,7 @@ func (a *Account) Withdraw(b types.Balance) *types.FLOWTokenVault { a.address, b.ToAttoFlow(), ) - a.executeAndHandleCall(a.fch.getBlockContext(), call, b.ToAttoFlow().Uint64(), true) + a.executeAndHandleCall(a.fch.getBlockContext(), call, b.ToAttoFlow(), true) return types.NewFlowTokenVault(b) } @@ -238,7 +232,7 @@ func (a *Account) Transfer(to types.Address, balance types.Balance) { to, balance.ToAttoFlow(), ) - a.executeAndHandleCall(ctx, call, 0, false) + a.executeAndHandleCall(ctx, call, nil, false) } // Deploy deploys a contract to the EVM environment @@ -254,7 +248,7 @@ func (a *Account) Deploy(code types.Code, gaslimit types.GasLimit, balance types uint64(gaslimit), balance.ToAttoFlow(), ) - res := a.executeAndHandleCall(a.fch.getBlockContext(), call, 0, false) + res := a.executeAndHandleCall(a.fch.getBlockContext(), call, nil, false) return types.Address(res.DeployedContractAddress) } @@ -272,14 +266,14 @@ func (a *Account) Call(to types.Address, data types.Data, gaslimit types.GasLimi uint64(gaslimit), balance.ToAttoFlow(), ) - res := a.executeAndHandleCall(a.fch.getBlockContext(), call, 0, false) + res := a.executeAndHandleCall(a.fch.getBlockContext(), call, nil, false) return res.ReturnedValue } func (a *Account) executeAndHandleCall( ctx types.BlockContext, call *types.DirectCall, - totalSupplyDiff uint64, + totalSupplyDiff *big.Int, deductSupplyDiff bool, ) *types.Result { // execute the call @@ -300,11 +294,13 @@ func (a *Account) executeAndHandleCall( bp, err := a.fch.blockstore.BlockProposal() handleError(err) bp.AppendTxHash(callHash) - if deductSupplyDiff { - bp.TotalSupply -= totalSupplyDiff - } else { - // TODO: add overflow errors (even though we might never get there) - bp.TotalSupply += totalSupplyDiff + if totalSupplyDiff != nil { + if deductSupplyDiff { + bp.TotalSupply = new(big.Int).Sub(bp.TotalSupply, totalSupplyDiff) + } else { + bp.TotalSupply = new(big.Int).Add(bp.TotalSupply, totalSupplyDiff) + } + } // emit events diff --git a/fvm/evm/types/block.go b/fvm/evm/types/block.go index 88d7f930502..9ec08551104 100644 --- a/fvm/evm/types/block.go +++ b/fvm/evm/types/block.go @@ -1,6 +1,8 @@ package types import ( + "math/big" + gethCommon "github.com/ethereum/go-ethereum/common" gethTypes "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/rlp" @@ -15,8 +17,8 @@ type Block struct { // Height returns the height of this block Height uint64 - // holds the total amount of the native token deposited in the evm side. - TotalSupply uint64 + // holds the total amount of the native token deposited in the evm side. (in attoflow) + TotalSupply *big.Int // ReceiptRoot returns the root hash of the receipts emitted in this block ReceiptRoot gethCommon.Hash @@ -42,7 +44,7 @@ func (b *Block) AppendTxHash(txHash gethCommon.Hash) { } // NewBlock constructs a new block -func NewBlock(height, uuidIndex, totalSupply uint64, +func NewBlock(height, uuidIndex uint64, totalSupply *big.Int, stateRoot, receiptRoot gethCommon.Hash, txHashes []gethCommon.Hash, ) *Block { @@ -65,5 +67,6 @@ func NewBlockFromBytes(encoded []byte) (*Block, error) { var GenesisBlock = &Block{ ParentBlockHash: gethCommon.Hash{}, Height: uint64(0), + TotalSupply: new(big.Int), ReceiptRoot: gethTypes.EmptyRootHash, } diff --git a/fvm/evm/types/events.go b/fvm/evm/types/events.go index f69da8efef6..f8afcf2c040 100644 --- a/fvm/evm/types/events.go +++ b/fvm/evm/types/events.go @@ -169,7 +169,7 @@ var blockExecutedEventCadenceType = &cadence.EventType{ Fields: []cadence.Field{ cadence.NewField("height", cadence.UInt64Type{}), cadence.NewField("hash", cadence.StringType{}), - cadence.NewField("totalSupply", cadence.UInt64Type{}), + cadence.NewField("totalSupply", cadence.IntType{}), cadence.NewField("parentHash", cadence.StringType{}), cadence.NewField("receiptRoot", cadence.StringType{}), cadence.NewField( @@ -197,7 +197,7 @@ func (p *BlockExecutedEventPayload) CadenceEvent() (cadence.Event, error) { fields := []cadence.Value{ cadence.NewUInt64(p.Block.Height), cadence.String(blockHash.String()), - cadence.NewUInt64(p.Block.TotalSupply), + cadence.NewIntFromBig(p.Block.TotalSupply), cadence.String(p.Block.ParentBlockHash.String()), cadence.String(p.Block.ReceiptRoot.String()), cadence.NewArray(hashes).WithType(cadence.NewVariableSizedArrayType(cadence.StringType{})),