Skip to content

Commit

Permalink
Account for query bit when switching on txn version for hashing
Browse files Browse the repository at this point in the history
  • Loading branch information
omerfirmak committed Sep 15, 2023
1 parent 1b3f067 commit 6dd0957
Show file tree
Hide file tree
Showing 7 changed files with 113 additions and 61 deletions.
8 changes: 4 additions & 4 deletions adapters/feeder2core/feeder2core.go
Original file line number Diff line number Diff line change
Expand Up @@ -164,7 +164,7 @@ func AdaptDeclareTransaction(t *feeder.Transaction) *core.DeclareTransaction {
MaxFee: t.MaxFee,
TransactionSignature: *t.Signature,
Nonce: t.Nonce,
Version: t.Version,
Version: (*core.TransactionVersion)(t.Version),
ClassHash: t.ClassHash,
CompiledClassHash: t.CompiledClassHash,
}
Expand All @@ -180,7 +180,7 @@ func AdaptDeployTransaction(t *feeder.Transaction) *core.DeployTransaction {
ContractAddress: t.ContractAddress,
ClassHash: t.ClassHash,
ConstructorCallData: *t.ConstructorCallData,
Version: t.Version,
Version: (*core.TransactionVersion)(t.Version),
}
}

Expand All @@ -193,7 +193,7 @@ func AdaptInvokeTransaction(t *feeder.Transaction) *core.InvokeTransaction {
CallData: *t.CallData,
TransactionSignature: *t.Signature,
MaxFee: t.MaxFee,
Version: t.Version,
Version: (*core.TransactionVersion)(t.Version),
SenderAddress: t.SenderAddress,
}
}
Expand All @@ -205,7 +205,7 @@ func AdaptL1HandlerTransaction(t *feeder.Transaction) *core.L1HandlerTransaction
EntryPointSelector: t.EntryPointSelector,
Nonce: t.Nonce,
CallData: *t.CallData,
Version: t.Version,
Version: (*core.TransactionVersion)(t.Version),
}
}

Expand Down
10 changes: 5 additions & 5 deletions adapters/feeder2core/feeder2core_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -228,7 +228,7 @@ func TestTransaction(t *testing.T) {
assert.Equal(t, *responseTx.CallData, invokeTx.CallData)
assert.Equal(t, *responseTx.Signature, invokeTx.Signature())
assert.Equal(t, responseTx.MaxFee, invokeTx.MaxFee)
assert.Equal(t, responseTx.Version, invokeTx.Version)
assert.Equal(t, responseTx.Version, invokeTx.Version.AsFelt())
})

t.Run("deploy transaction", func(t *testing.T) {
Expand All @@ -248,7 +248,7 @@ func TestTransaction(t *testing.T) {
assert.Equal(t, responseTx.ContractAddress, deployTx.ContractAddress)
assert.Equal(t, responseTx.ClassHash, deployTx.ClassHash)
assert.Equal(t, *responseTx.ConstructorCallData, deployTx.ConstructorCallData)
assert.Equal(t, responseTx.Version, deployTx.Version)
assert.Equal(t, responseTx.Version, deployTx.Version.AsFelt())
})

t.Run("deploy account transaction", func(t *testing.T) {
Expand All @@ -268,7 +268,7 @@ func TestTransaction(t *testing.T) {
assert.Equal(t, responseTx.ContractAddress, deployAccountTx.ContractAddress)
assert.Equal(t, responseTx.ClassHash, deployAccountTx.ClassHash)
assert.Equal(t, *responseTx.ConstructorCallData, deployAccountTx.ConstructorCallData)
assert.Equal(t, responseTx.Version, deployAccountTx.Version)
assert.Equal(t, responseTx.Version, deployAccountTx.Version.AsFelt())
assert.Equal(t, responseTx.MaxFee, deployAccountTx.MaxFee)
assert.Equal(t, *responseTx.Signature, deployAccountTx.Signature())
assert.Equal(t, responseTx.Nonce, deployAccountTx.Nonce)
Expand All @@ -288,7 +288,7 @@ func TestTransaction(t *testing.T) {

assert.Equal(t, responseTx.Hash, declareTx.Hash())
assert.Equal(t, responseTx.SenderAddress, declareTx.SenderAddress)
assert.Equal(t, responseTx.Version, declareTx.Version)
assert.Equal(t, responseTx.Version, declareTx.Version.AsFelt())
assert.Equal(t, responseTx.Nonce, declareTx.Nonce)
assert.Equal(t, responseTx.MaxFee, declareTx.MaxFee)
assert.Equal(t, *responseTx.Signature, declareTx.Signature())
Expand All @@ -312,7 +312,7 @@ func TestTransaction(t *testing.T) {
assert.Equal(t, responseTx.EntryPointSelector, l1HandlerTx.EntryPointSelector)
assert.Equal(t, responseTx.Nonce, l1HandlerTx.Nonce)
assert.Equal(t, *responseTx.CallData, l1HandlerTx.CallData)
assert.Equal(t, responseTx.Version, l1HandlerTx.Version)
assert.Equal(t, responseTx.Version, l1HandlerTx.Version.AsFelt())
})
}

Expand Down
97 changes: 73 additions & 24 deletions core/transaction.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import (
"encoding/binary"
"errors"
"fmt"
"math/big"
"runtime"
"strings"
"sync"
Expand All @@ -15,6 +16,7 @@ import (
"github.com/NethermindEth/juno/utils"
"github.com/bits-and-blooms/bloom/v3"
"github.com/ethereum/go-ethereum/common"
"github.com/fxamacker/cbor/v2"
"github.com/sourcegraph/conc/pool"
)

Expand Down Expand Up @@ -70,20 +72,67 @@ type Transaction interface {
}

var (
_ Transaction = (*DeployTransaction)(nil)
_ Transaction = (*DeployAccountTransaction)(nil)
_ Transaction = (*DeclareTransaction)(nil)
_ Transaction = (*InvokeTransaction)(nil)
_ Transaction = (*L1HandlerTransaction)(nil)
_ Transaction = (*DeployTransaction)(nil)
_ Transaction = (*DeployAccountTransaction)(nil)
_ Transaction = (*DeclareTransaction)(nil)
_ Transaction = (*InvokeTransaction)(nil)
_ Transaction = (*L1HandlerTransaction)(nil)
queryVersion = new(felt.Felt).Exp(new(felt.Felt).SetUint64(2), new(big.Int).SetUint64(queryBit))
)

const (
// Calculated at https://hur.st/bloomfilter/?n=1000&p=&m=8192&k=
// provides 1 in 51 possibility of false positives for approximately 1000 elements
eventsBloomLength = 8192
eventsBloomHashFuncs = 6
queryBit = 128
)

// Keep in mind that this is used as a storage type, make sure you migrate
// the DB if you change the underlying type
type TransactionVersion felt.Felt

func (v *TransactionVersion) SetUint64(u64 uint64) *TransactionVersion {
v.AsFelt().SetUint64(u64)
return v
}

func (v *TransactionVersion) HasQueryBit() bool {
// if versionWithoutQueryBit >= queryBit
return v.AsFelt().Cmp(queryVersion) != -1
}

// Is compares the version (without query bit) with the given value
func (v *TransactionVersion) Is(u64 uint64) bool {
var tmpV TransactionVersion
tmpV.SetUint64(u64)
return tmpV == v.WithoutQueryBit()
}

func (v *TransactionVersion) WithoutQueryBit() TransactionVersion {
vFelt := felt.Felt(*v)
if v.HasQueryBit() {
vFelt.Sub(&vFelt, queryVersion)
}
return TransactionVersion(vFelt)
}

func (v *TransactionVersion) String() string {
return v.AsFelt().String()
}

func (v *TransactionVersion) AsFelt() *felt.Felt {
return (*felt.Felt)(v)
}

func (v *TransactionVersion) MarshalCBOR() ([]byte, error) {
return cbor.Marshal(v.AsFelt())
}

func (v *TransactionVersion) UnmarshalCBOR(data []byte) error {
return cbor.Unmarshal(data, v.AsFelt())
}

type DeployTransaction struct {
TransactionHash *felt.Felt
// A random number used to distinguish between different instances of the contract.
Expand All @@ -100,7 +149,7 @@ type DeployTransaction struct {
// either with the addition of a new field or the removal of an existing field,
// then the transaction version increases.
// Transaction version 0 is deprecated and will be removed in a future version of Starknet.
Version *felt.Felt
Version *TransactionVersion
}

func (d *DeployTransaction) Hash() *felt.Felt {
Expand Down Expand Up @@ -142,7 +191,7 @@ type InvokeTransaction struct {
// When the fields that comprise a transaction change,
// either with the addition of a new field or the removal of an existing field,
// then the transaction version increases.
Version *felt.Felt
Version *TransactionVersion

// Version 0 fields
// The encoding of the selector for the function invoked (the entry point in the contract)
Expand Down Expand Up @@ -180,7 +229,7 @@ type DeclareTransaction struct {
// either with the addition of a new field or the removal of an existing field,
// then the transaction version increases.
// Transaction version 0 is deprecated and will be removed in a future version of Starknet.
Version *felt.Felt
Version *TransactionVersion

// Version 2 fields
CompiledClassHash *felt.Felt
Expand All @@ -207,7 +256,7 @@ type L1HandlerTransaction struct {
// When the fields that comprise a transaction change,
// either with the addition of a new field or the removal of an existing field,
// then the transaction version increases.
Version *felt.Felt
Version *TransactionVersion
}

func (l *L1HandlerTransaction) Hash() *felt.Felt {
Expand Down Expand Up @@ -244,26 +293,26 @@ var (
deployAccountFelt = new(felt.Felt).SetBytes([]byte("deploy_account"))
)

func errInvalidTransactionVersion(t Transaction, version *felt.Felt) error {
return fmt.Errorf("invalid Transaction (type: %T) version: %v", t, version.Text(felt.Base10))
func errInvalidTransactionVersion(t Transaction, version *TransactionVersion) error {
return fmt.Errorf("invalid Transaction (type: %T) version: %s", t, version)
}

func invokeTransactionHash(i *InvokeTransaction, n utils.Network) (*felt.Felt, error) {
switch {
case i.Version.IsZero():
case i.Version.Is(0):
return crypto.PedersenArray(
invokeFelt,
i.Version,
i.Version.AsFelt(),
i.ContractAddress,
i.EntryPointSelector,
crypto.PedersenArray(i.CallData...),
i.MaxFee,
n.ChainID(),
), nil
case i.Version.IsOne():
case i.Version.Is(1):
return crypto.PedersenArray(
invokeFelt,
i.Version,
i.Version.AsFelt(),
i.SenderAddress,
new(felt.Felt),
crypto.PedersenArray(i.CallData...),
Expand All @@ -278,24 +327,24 @@ func invokeTransactionHash(i *InvokeTransaction, n utils.Network) (*felt.Felt, e

func declareTransactionHash(d *DeclareTransaction, n utils.Network) (*felt.Felt, error) {
switch {
case d.Version.IsZero():
case d.Version.Is(0):
// Due to inconsistencies in version 0 hash calculation we don't verify the hash
return d.TransactionHash, nil
case d.Version.IsOne():
case d.Version.Is(1):
return crypto.PedersenArray(
declareFelt,
d.Version,
d.Version.AsFelt(),
d.SenderAddress,
new(felt.Felt),
crypto.PedersenArray(d.ClassHash),
d.MaxFee,
n.ChainID(),
d.Nonce,
), nil
case d.Version.Equal(new(felt.Felt).SetUint64(2)):
case d.Version.Is(2):
return crypto.PedersenArray(
declareFelt,
d.Version,
d.Version.AsFelt(),
d.SenderAddress,
&felt.Zero,
crypto.PedersenArray(d.ClassHash),
Expand All @@ -312,15 +361,15 @@ func declareTransactionHash(d *DeclareTransaction, n utils.Network) (*felt.Felt,

func l1HandlerTransactionHash(l *L1HandlerTransaction, n utils.Network) (*felt.Felt, error) {
switch {
case l.Version.IsZero():
case l.Version.Is(0):
// There are some l1 handler transaction which do not return a nonce and for some random
// transaction the following hash fails.
if l.Nonce == nil {
return l.TransactionHash, nil
}
return crypto.PedersenArray(
l1HandlerFelt,
l.Version,
l.Version.AsFelt(),
l.ContractAddress,
l.EntryPointSelector,
crypto.PedersenArray(l.CallData...),
Expand All @@ -337,10 +386,10 @@ func deployAccountTransactionHash(d *DeployAccountTransaction, n utils.Network)
callData := []*felt.Felt{d.ClassHash, d.ContractAddressSalt}
callData = append(callData, d.ConstructorCallData...)
// There is no version 0 for deploy account
if d.Version.IsOne() {
if d.Version.Is(1) {
return crypto.PedersenArray(
deployAccountFelt,
d.Version,
d.Version.AsFelt(),
d.ContractAddress,
&felt.Zero,
crypto.PedersenArray(callData...),
Expand Down
30 changes: 23 additions & 7 deletions core/transaction_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ func TestTransactionEncoding(t *testing.T) {
new(felt.Felt).SetUint64(6),
},
Nonce: new(felt.Felt).SetUint64(7),
Version: new(felt.Felt).SetUint64(8),
Version: new(core.TransactionVersion).SetUint64(8),
},
},
{
Expand All @@ -48,7 +48,7 @@ func TestTransactionEncoding(t *testing.T) {
new(felt.Felt).SetUint64(5),
new(felt.Felt).SetUint64(6),
},
Version: new(felt.Felt).SetUint64(7),
Version: new(core.TransactionVersion).SetUint64(7),
},
},
{
Expand All @@ -65,7 +65,7 @@ func TestTransactionEncoding(t *testing.T) {
},
MaxFee: new(felt.Felt).SetUint64(6),
ContractAddress: new(felt.Felt).SetUint64(7),
Version: new(felt.Felt).SetUint64(8),
Version: new(core.TransactionVersion).SetUint64(8),
EntryPointSelector: new(felt.Felt).SetUint64(9),
Nonce: new(felt.Felt).SetUint64(10),
},
Expand All @@ -82,7 +82,7 @@ func TestTransactionEncoding(t *testing.T) {
new(felt.Felt).SetUint64(5),
new(felt.Felt).SetUint64(6),
},
Version: new(felt.Felt).SetUint64(7),
Version: new(core.TransactionVersion).SetUint64(7),
},
MaxFee: new(felt.Felt).SetUint64(8),
TransactionSignature: []*felt.Felt{
Expand All @@ -103,7 +103,7 @@ func TestTransactionEncoding(t *testing.T) {
new(felt.Felt).SetUint64(5),
new(felt.Felt).SetUint64(6),
},
Version: new(felt.Felt).SetUint64(7),
Version: new(core.TransactionVersion).SetUint64(7),
},
},
}
Expand Down Expand Up @@ -168,7 +168,7 @@ func TestVerifyTransactionHash(t *testing.T) {
t.Run("contains bad transaction", func(t *testing.T) {
badTxn0 := new(core.DeclareTransaction)
*badTxn0 = *txn0.(*core.DeclareTransaction)
badTxn0.Version = new(felt.Felt).SetUint64(3)
badTxn0.Version = new(core.TransactionVersion).SetUint64(3)

badTxn1 := new(core.L1HandlerTransaction)
*badTxn1 = *txn3.(*core.L1HandlerTransaction)
Expand All @@ -181,7 +181,7 @@ func TestVerifyTransactionHash(t *testing.T) {
}{
*badTxn0.Hash(): {
name: "Declare - error if transaction hash calculation failed",
wantErr: fmt.Errorf("cannot calculate transaction hash of Transaction %v, reason: %w", badTxn0.Hash().String(), errors.New("invalid Transaction (type: *core.DeclareTransaction) version: 3")),
wantErr: fmt.Errorf("cannot calculate transaction hash of Transaction %v, reason: %w", badTxn0.Hash().String(), errors.New("invalid Transaction (type: *core.DeclareTransaction) version: 0x3")),
txn: badTxn0,
},
*badTxn1.Hash(): {
Expand Down Expand Up @@ -209,3 +209,19 @@ func TestVerifyTransactionHash(t *testing.T) {
assert.NoError(t, core.VerifyTransactions(txns, utils.MAINNET, "99.99.99"))
})
}

func TestTransactionVersi(t *testing.T) {
f := utils.HexToFelt(t, "0x100000000000000000000000000000002")
v := (*core.TransactionVersion)(f)

assert.True(t, v.HasQueryBit())
assert.True(t, v.Is(2))
assert.False(t, v.Is(1))
assert.False(t, v.Is(0))

withoutQBit := v.WithoutQueryBit()
assert.False(t, withoutQBit.HasQueryBit())
assert.True(t, withoutQBit.Is(2))
assert.False(t, withoutQBit.Is(1))
assert.False(t, withoutQBit.Is(0))
}
Loading

0 comments on commit 6dd0957

Please sign in to comment.