Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

New message #34

Merged
merged 1 commit into from
Dec 25, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
111 changes: 111 additions & 0 deletions new_substate/message.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
package new_substate

import (
"bytes"
"math/big"

"github.com/Fantom-foundation/Substate/geth/common"
"github.com/Fantom-foundation/Substate/geth/crypto"
"github.com/Fantom-foundation/Substate/geth/types"
)

type Message struct {
Nonce uint64
CheckNonce bool // inversion of IsFake
GasPrice *big.Int
Gas uint64

From common.Address
To *common.Address // nil means contract creation
Value *big.Int
Data []byte

// for memoization
dataHash *common.Hash

// Berlin hard fork, EIP-2930: Optional access lists
AccessList types.AccessList // nil if EIP-2930 is not activated

// London hard fork, EIP-1559: Fee market
GasFeeCap *big.Int // GasPrice if EIP-1559 is not activated
GasTipCap *big.Int // GasPrice if EIP-1559 is not activated
}

func NewMessage(nonce uint64, checkNonce bool, gasPrice *big.Int, gas uint64, from common.Address, to *common.Address, value *big.Int, data []byte, dataHash *common.Hash, accessList types.AccessList, gasFeeCap *big.Int, gasTipCap *big.Int) *Message {
return &Message{
Nonce: nonce,
CheckNonce: checkNonce,
GasPrice: gasPrice,
Gas: gas,
From: from,
To: to,
Value: value,
Data: data,
dataHash: dataHash,
AccessList: accessList,
GasFeeCap: gasFeeCap,
GasTipCap: gasTipCap,
}
}

// Equal returns true if m is y or if values of m are equal to values of y.
// Otherwise, m and y are not equal hence false is returned.
func (m *Message) Equal(y *Message) bool {
if m == y {
return true
}

if (m == nil || y == nil) && m != y {
return false
}

// check values
equal := m.Nonce == y.Nonce &&
m.CheckNonce == y.CheckNonce &&
m.GasPrice.Cmp(y.GasPrice) == 0 &&
m.Gas == y.Gas &&
m.From == y.From &&
(m.To == y.To || (m.To != nil && y.To != nil && *m.To == *y.To)) &&
m.Value.Cmp(y.Value) == 0 &&
bytes.Equal(m.Data, y.Data) &&
len(m.AccessList) == len(y.AccessList) &&
m.GasFeeCap.Cmp(y.GasFeeCap) == 0 &&
m.GasTipCap.Cmp(y.GasTipCap) == 0
if !equal {
return false
}

// check AccessList
for i, mTuple := range m.AccessList {
yTuple := y.AccessList[i]

// check addresses position
if mTuple.Address != yTuple.Address {
return false
}

// check size of StorageKeys
if len(mTuple.StorageKeys) != len(yTuple.StorageKeys) {
return false
}

// check StorageKeys
for j, mKey := range mTuple.StorageKeys {
yKey := yTuple.StorageKeys[j]
if mKey != yKey {
return false
}
}
}

return true
}

// DataHash returns m.dataHash if it exists. If not, it is generated using Keccak256 algorithm.
func (m *Message) DataHash() common.Hash {
if m.dataHash == nil {
dataHash := crypto.Keccak256Hash(m.Data)
m.dataHash = &dataHash
}
return *m.dataHash
}
189 changes: 189 additions & 0 deletions new_substate/message_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,189 @@
package new_substate

import (
"math/big"
"testing"

"github.com/Fantom-foundation/Substate/geth/common"
"github.com/Fantom-foundation/Substate/geth/crypto"
"github.com/Fantom-foundation/Substate/geth/types"
)

func TestMessage_EqualNonce(t *testing.T) {
msg := &Message{Nonce: 0}
comparedMsg := &Message{Nonce: 1}

if msg.Equal(comparedMsg) {
t.Fatal("messages nonce are different but equal returned true")
}

comparedMsg.Nonce = msg.Nonce
if !msg.Equal(comparedMsg) {
t.Fatal("messages nonce are same but equal returned false")
}
}

func TestMessage_EqualCheckNonce(t *testing.T) {
msg := &Message{CheckNonce: false}
comparedMsg := &Message{CheckNonce: true}

if msg.Equal(comparedMsg) {
t.Fatal("messages CheckNonce are different but equal returned true")
}

comparedMsg.CheckNonce = msg.CheckNonce
if !msg.Equal(comparedMsg) {
t.Fatal("messages CheckNonce are same but equal returned false")
}
}

func TestMessage_EqualGasPrice(t *testing.T) {
msg := &Message{GasPrice: new(big.Int).SetUint64(0)}
comparedMsg := &Message{GasPrice: new(big.Int).SetUint64(1)}

if msg.Equal(comparedMsg) {
t.Fatal("messages GasPrice are different but equal returned true")
}

comparedMsg.GasPrice = msg.GasPrice
if !msg.Equal(comparedMsg) {
t.Fatal("messages GasPrice are same but equal returned false")
}
}

func TestMessage_EqualFrom(t *testing.T) {
msg := &Message{From: common.Address{0}}
comparedMsg := &Message{From: common.Address{1}}

if msg.Equal(comparedMsg) {
t.Fatal("messages From are different but equal returned true")
}

comparedMsg.From = msg.From
if !msg.Equal(comparedMsg) {
t.Fatal("messages From are same but equal returned false")
}
}

func TestMessage_EqualTo(t *testing.T) {
msg := &Message{To: &common.Address{0}}
comparedMsg := &Message{To: &common.Address{1}}

if msg.Equal(comparedMsg) {
t.Fatal("messages To are different but equal returned true")
}

comparedMsg.To = msg.To
if !msg.Equal(comparedMsg) {
t.Fatal("messages To are same but equal returned false")
}
}

func TestMessage_EqualValue(t *testing.T) {
msg := &Message{Value: new(big.Int).SetUint64(0)}
comparedMsg := &Message{Value: new(big.Int).SetUint64(1)}

if msg.Equal(comparedMsg) {
t.Fatal("messages values are different but equal returned true")
}

comparedMsg.Value = msg.Value
if !msg.Equal(comparedMsg) {
t.Fatal("messages Value are same but equal returned false")
}
}

func TestMessage_Equal_DataHashDoesNotAffectResult(t *testing.T) {
msg := &Message{dataHash: new(common.Hash)}
*msg.dataHash = common.BytesToHash([]byte{0})
comparedMsg := &Message{dataHash: new(common.Hash)}
*comparedMsg.dataHash = common.BytesToHash([]byte{1})

if !msg.Equal(comparedMsg) {
t.Fatal("dataHash must not affect equal even if it is different")
}

comparedMsg.dataHash = msg.dataHash
if !msg.Equal(comparedMsg) {
t.Fatal("dataHash must not affect equal")
}
}

func TestMessage_EqualAccessList(t *testing.T) {
msg := &Message{AccessList: []types.AccessTuple{{Address: common.Address{0}, StorageKeys: []common.Hash{common.BytesToHash([]byte{0})}}}}
comparedMsg := &Message{AccessList: []types.AccessTuple{{Address: common.Address{0}, StorageKeys: []common.Hash{common.BytesToHash([]byte{1})}}}}

if msg.Equal(comparedMsg) {
t.Fatal("messages access list have different Storage Key for same address but equal returned true")
}

comparedMsg.AccessList = append(comparedMsg.AccessList, types.AccessTuple{Address: common.Address{0}, StorageKeys: []common.Hash{common.BytesToHash([]byte{0})}})
if msg.Equal(comparedMsg) {
t.Fatal("messages access list have different Storage Keys for same address but equal returned true")
}

comparedMsg = &Message{AccessList: []types.AccessTuple{{Address: common.Address{1}, StorageKeys: []common.Hash{common.BytesToHash([]byte{1})}}}}
if msg.Equal(comparedMsg) {
t.Fatal("messages access list have different AccessList but equal returned true")
}

comparedMsg.AccessList = msg.AccessList
if !msg.Equal(comparedMsg) {
t.Fatal("messages Value are same but equal returned false")
}
}

func TestMessage_EqualGasFeeCap(t *testing.T) {
msg := &Message{GasFeeCap: new(big.Int).SetUint64(0)}
comparedMsg := &Message{GasFeeCap: new(big.Int).SetUint64(1)}

if msg.Equal(comparedMsg) {
t.Fatal("messages GasFeeCap are different but equal returned true")
}

comparedMsg.GasFeeCap = msg.GasFeeCap
if !msg.Equal(comparedMsg) {
t.Fatal("messages GasFeeCap are same but equal returned false")
}
}

func TestMessage_EqualGasTipCap(t *testing.T) {
msg := &Message{GasTipCap: new(big.Int).SetUint64(0)}
comparedMsg := &Message{GasTipCap: new(big.Int).SetUint64(1)}

if msg.Equal(comparedMsg) {
t.Fatal("messages GasTipCap are different but equal returned true")
}

comparedMsg.GasTipCap = msg.GasTipCap
if !msg.Equal(comparedMsg) {
t.Fatal("messages GasTipCap are same but equal returned false")
}
}

func TestMessage_DataHashReturnsIfExists(t *testing.T) {
want := common.BytesToHash([]byte{1})
msg := &Message{dataHash: &want}

got := msg.DataHash()
if want != got {
t.Fatalf("hashes are different\nwant: %v\ngot: %v", want, got)
}

}

func TestMessage_DataHashGeneratesNewHashIfNil(t *testing.T) {
msg := &Message{Data: []byte{1}}
got := msg.DataHash()

want := crypto.Keccak256Hash(msg.Data)

if got == common.EmptyHash {
t.Fatal("dataHash is nil")
}

if want != got {
t.Fatalf("hashes are different\nwant: %v\ngot: %v", want, got)
}

}