Skip to content

Commit

Permalink
feat: add withdrawal transaction info hashing
Browse files Browse the repository at this point in the history
  • Loading branch information
sircoon4 committed Aug 8, 2024
1 parent 5397747 commit e4d3bc4
Show file tree
Hide file tree
Showing 5 changed files with 134 additions and 12 deletions.
65 changes: 55 additions & 10 deletions core/vm/contracts.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
package vm

import (
"crypto/sha1"
"crypto/sha256"
"encoding/binary"
"errors"
Expand All @@ -33,6 +34,8 @@ import (
"github.com/ethereum/go-ethereum/crypto/secp256r1"
"github.com/ethereum/go-ethereum/libplanet"
"github.com/ethereum/go-ethereum/params"
"github.com/sircoon4/bencodex-go"
"github.com/sircoon4/bencodex-go/bencodextype"
"golang.org/x/crypto/ripemd160"
)

Expand Down Expand Up @@ -83,15 +86,17 @@ var PrecompiledContractsIstanbul = map[common.Address]PrecompiledContract{
// PrecompiledContractsBerlin contains the default set of pre-compiled Ethereum
// contracts used in the Berlin release.
var PrecompiledContractsBerlin = map[common.Address]PrecompiledContract{
common.BytesToAddress([]byte{1}): &ecrecover{},
common.BytesToAddress([]byte{2}): &sha256hash{},
common.BytesToAddress([]byte{3}): &ripemd160hash{},
common.BytesToAddress([]byte{4}): &dataCopy{},
common.BytesToAddress([]byte{5}): &bigModExp{eip2565: true},
common.BytesToAddress([]byte{6}): &bn256AddIstanbul{},
common.BytesToAddress([]byte{7}): &bn256ScalarMulIstanbul{},
common.BytesToAddress([]byte{8}): &bn256PairingIstanbul{},
common.BytesToAddress([]byte{9}): &blake2F{},
common.BytesToAddress([]byte{1}): &ecrecover{},
common.BytesToAddress([]byte{2}): &sha256hash{},
common.BytesToAddress([]byte{3}): &ripemd160hash{},
common.BytesToAddress([]byte{4}): &dataCopy{},
common.BytesToAddress([]byte{5}): &bigModExp{eip2565: true},
common.BytesToAddress([]byte{6}): &bn256AddIstanbul{},
common.BytesToAddress([]byte{7}): &bn256ScalarMulIstanbul{},
common.BytesToAddress([]byte{8}): &bn256PairingIstanbul{},
common.BytesToAddress([]byte{9}): &blake2F{},
common.BytesToAddress([]byte{0x02, 0x00}): &libplanetVerifyProof{},
common.BytesToAddress([]byte{0x02, 0x01}): &libplanetWithdrawalTransactionHashing{},
}

// PrecompiledContractsCancun contains the default set of pre-compiled Ethereum
Expand Down Expand Up @@ -124,6 +129,7 @@ var PrecompiledContractsFjord = map[common.Address]PrecompiledContract{
common.BytesToAddress([]byte{0x0a}): &kzgPointEvaluation{},
common.BytesToAddress([]byte{0x01, 0x00}): &p256Verify{},
common.BytesToAddress([]byte{0x02, 0x00}): &libplanetVerifyProof{},
common.BytesToAddress([]byte{0x02, 0x01}): &libplanetWithdrawalTransactionHashing{},
}

// PrecompiledContractsBLS contains the set of pre-compiled Ethereum
Expand Down Expand Up @@ -1206,7 +1212,7 @@ func (c *libplanetVerifyProof) Run(input []byte) ([]byte, error) {
proofMap := map[string]any{
"stateRootHash": nil, // sha256(bencoded) []byte
"proof": nil, // bencoded(list) []byte
"key": nil, // keyBytes []byte
"key": nil, // keyBytes | address []byte
"value": nil, // bencoded []byte
}
proofMap, err := libplanet.ParseMerkleTrieProofInput(input)
Expand All @@ -1223,3 +1229,42 @@ func (c *libplanetVerifyProof) Run(input []byte) ([]byte, error) {

return common.CopyBytes(libplanet.BoolAbi(valid)), nil
}

type libplanetWithdrawalTransactionHashing struct{}

func (c *libplanetWithdrawalTransactionHashing) RequiredGas(input []byte) uint64 {
return params.LibplanetWithdrawalTransactionHashingGas
}

func (c *libplanetWithdrawalTransactionHashing) Run(input []byte) ([]byte, error) {
withdrawalTransaction := map[string]any{
"nonce": nil, // *big.Int
"from": nil, // common.Address
"to": nil, // common.Address
"amount": nil, // *big.Int
}
withdrawalTransaction, err := libplanet.ParseWithdrawalTransactionInput(input)
if err != nil {
return nil, err
}

nonce := withdrawalTransaction["nonce"].(*big.Int)
from := withdrawalTransaction["from"].(common.Address).Bytes()
to := withdrawalTransaction["to"].(common.Address).Bytes()
amount := withdrawalTransaction["amount"].(*big.Int)

dict := bencodextype.NewDictionary()
dict.Set("nonce", nonce)
dict.Set("from", from)
dict.Set("to", to)
dict.Set("amount", amount)

encoded, err := bencodex.Encode(dict)
if err != nil {
return nil, err
}

sum := sha1.Sum(encoded)

return common.CopyBytes(libplanet.AddressAbi(sum)), nil
}
4 changes: 4 additions & 0 deletions libplanet/merkle_trie_proof.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,10 @@ func ValidateProof(
key []byte, // []byte
value []byte, // bencoded
) (bool, error) {
key, err := validProofKey(key)
if err != nil {
return false, err
}
targetHash := stateRootHash
nibbles := keybytesToNibbles(key)
decodedProofList, err := bencodex.Decode(proof)
Expand Down
26 changes: 26 additions & 0 deletions libplanet/merkle_trie_proof_utils.go
Original file line number Diff line number Diff line change
Expand Up @@ -120,3 +120,29 @@ func resolveToNextCandidateNode(

return nil, nil, fmt.Errorf("invalid proof node")
}

func validProofKey(key []byte) ([]byte, error) {
if len(key) == 20 {
return toStateKey(key), nil
}

if len(key) == 40 {
return key, nil
}

return nil, fmt.Errorf("invalid key length")
}

func toStateKey(key []byte) []byte {
var _conversionTable = []byte{
48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 97, 98, 99, 100, 101, 102,
}

l := len(key)
var stateKey = make([]byte, l*2)
for i, b := range key {
stateKey[i*2] = _conversionTable[b>>4]
stateKey[i*2+1] = _conversionTable[b&0xf]
}
return stateKey
}
46 changes: 46 additions & 0 deletions libplanet/withdrawal_transaction_utils.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
package libplanet

import (
"github.com/ethereum/go-ethereum/accounts/abi"
"github.com/ethereum/go-ethereum/common"
)

func ParseWithdrawalTransactionInput(input []byte) (map[string]any, error) {
Uint256, _ := abi.NewType("uint256", "", nil)
Address, _ := abi.NewType("address", "", nil)

var arguments = abi.Arguments{
abi.Argument{Name: "nonce", Type: Uint256, Indexed: false},
abi.Argument{Name: "from", Type: Address, Indexed: false},
abi.Argument{Name: "to", Type: Address, Indexed: false},
abi.Argument{Name: "amount", Type: Uint256, Indexed: false},
}

decoded := map[string]any{
"nonce": nil, // *big.Int
"from": nil, // common.Address
"to": nil, // common.Address
"amount": nil, // *big.Int
}
err := arguments.UnpackIntoMap(decoded, input)
if err != nil {
return nil, err
}

return decoded, nil
}

func AddressAbi(input [20]byte) []byte {

Address, _ := abi.NewType("address", "", nil)

var arguments = abi.Arguments{
abi.Argument{Name: "address", Type: Address, Indexed: false},
}

encoded, err := arguments.Pack(common.BytesToAddress(input[:]))
if err != nil {
panic(err)
}
return encoded
}
5 changes: 3 additions & 2 deletions params/protocol_params.go
Original file line number Diff line number Diff line change
Expand Up @@ -166,8 +166,9 @@ const (
Bls12381MapG1Gas uint64 = 5500 // Gas price for BLS12-381 mapping field element to G1 operation
Bls12381MapG2Gas uint64 = 110000 // Gas price for BLS12-381 mapping field element to G2 operation

P256VerifyGas uint64 = 3450 // secp256r1 elliptic curve signature verifier gas price
LibplanetVerifyProofGas uint64 = 3000 // Libplanet proof verifier gas price
P256VerifyGas uint64 = 3450 // secp256r1 elliptic curve signature verifier gas price
LibplanetVerifyProofGas uint64 = 3000 // Libplanet proof verifier gas price
LibplanetWithdrawalTransactionHashingGas uint64 = 3000 // Libplanet withdraw transaction hashing gas price

// The Refund Quotient is the cap on how much of the used gas can be refunded. Before EIP-3529,
// up to half the consumed gas could be refunded. Redefined as 1/5th in EIP-3529
Expand Down

0 comments on commit e4d3bc4

Please sign in to comment.