Skip to content
This repository has been archived by the owner on Mar 8, 2024. It is now read-only.

Update precompile addresses to be QIP2 compatible #72

Merged
merged 2 commits into from
Feb 29, 2024
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
15 changes: 14 additions & 1 deletion common/address.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ type Address struct {
inner AddressData
}

type AddressBytes [20]byte
type AddressBytes [AddressLength]byte

type AddressData interface {
Bytes() []byte
Expand Down Expand Up @@ -257,6 +257,19 @@ func HexToAddress(s string, nodeLocation Location) Address {
return BytesToAddress(FromHex(s), nodeLocation)
}

func HexToAddressBytes(s string) AddressBytes {
var a AddressBytes
a.SetBytes(FromHex(s))
return a
}

func (a *AddressBytes) SetBytes(b []byte) {
if len(b) > len(a) {
b = b[len(b)-AddressLength:]
}
copy(a[AddressLength-len(b):], b)
}

// IsHexAddress verifies whether a string can represent a valid hex-encoded
// Quai address or not.
func IsHexAddress(s string) bool {
Expand Down
3 changes: 3 additions & 0 deletions common/types_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -537,6 +537,9 @@ func TestHash_Format(t *testing.T) {
}

func TestZeroAddress(t *testing.T) {
t.Log(fmt.Sprintf("0x%x00000000000000000000000000000000000000", nodeLocation.BytePrefix()))
addr := HexToAddress("0x110000000000000000000000000000000000115", nodeLocation)
t.Log(fmt.Sprintf("0x%x000000000000000000000000000000000000%02x", nodeLocation.BytePrefix(), addr.Bytes20()[19]))
t.Log(ZeroAddress(nodeLocation).String())
internal, err := ZeroAddress(nodeLocation).InternalAddress()
if err != nil {
Expand Down
4 changes: 2 additions & 2 deletions core/headerchain.go
Original file line number Diff line number Diff line change
Expand Up @@ -1249,7 +1249,7 @@ func (hc *HeaderChain) fetchInputUtxos(view *types.UtxoViewpoint, block *types.B
txInFlight[tx.Hash()] = i
}

if types.IsCoinBaseTx(transactions[0]) {
if len(transactions) > 0 && types.IsCoinBaseTx(transactions[0]) {
transactions = transactions[1:]
}

Expand Down Expand Up @@ -1296,7 +1296,7 @@ func (hc *HeaderChain) fetchInputUtxos(view *types.UtxoViewpoint, block *types.B
func (hc *HeaderChain) verifyInputUtxos(view *types.UtxoViewpoint, block *types.Block, signer types.Signer) (*big.Int, error) { // should this be used instead of Verify

transactions := block.QiTransactions()
if types.IsCoinBaseTx(transactions[0]) {
if len(transactions) > 0 && types.IsCoinBaseTx(transactions[0]) {
transactions = transactions[1:]
}

Expand Down
6 changes: 3 additions & 3 deletions core/state_processor.go
Original file line number Diff line number Diff line change
Expand Up @@ -332,7 +332,7 @@ func (p *StateProcessor) Process(block *types.Block, etxSet types.EtxSet) (types
i++
}

if types.IsCoinBaseTx(block.QiTransactions()[0]) {
if len(block.QiTransactions()) > 0 && types.IsCoinBaseTx(block.QiTransactions()[0]) {
totalCoinbaseOut := big.NewInt(0)
for _, txOut := range block.QiTransactions()[0].TxOut() {
totalCoinbaseOut.Add(totalCoinbaseOut, types.Denominations[txOut.Denomination])
Expand Down Expand Up @@ -911,7 +911,7 @@ func (p *StateProcessor) FetchInputUtxos(statedb *state.StateDB, view *types.Utx
for i, tx := range transactions {
txInFlight[tx.Hash()] = i
}
if types.IsCoinBaseTx(transactions[0]) {
if len(transactions) > 0 && types.IsCoinBaseTx(transactions[0]) {
transactions = transactions[1:]
}
// Loop through all of the transaction inputs (except for the coinbase
Expand Down Expand Up @@ -957,7 +957,7 @@ func (p *StateProcessor) FetchInputUtxos(statedb *state.StateDB, view *types.Utx
func (p *StateProcessor) VerifyTransactions(view *types.UtxoViewpoint, block *types.Block, signer types.Signer) (*big.Int, error) {

transactions := block.QiTransactions()
if types.IsCoinBaseTx(transactions[0]) {
if len(transactions) > 0 && types.IsCoinBaseTx(transactions[0]) {
transactions = transactions[1:]
}

Expand Down
2 changes: 1 addition & 1 deletion core/types/stxo.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ func CountSpentOutputs(block *Block) int {
if len(transactions) == 0 {
return 0
}
if IsCoinBaseTx(transactions[0]) {
if len(transactions) > 0 && IsCoinBaseTx(transactions[0]) {
transactions = transactions[1:]
}
// Exclude the coinbase transaction since it can't spend anything.
Expand Down
28 changes: 20 additions & 8 deletions core/types/transaction.go
Original file line number Diff line number Diff line change
Expand Up @@ -134,7 +134,11 @@ func (tx *Transaction) ProtoEncode() (*ProtoTransaction, error) {
protoTx.Gas = &gas
protoTx.AccessList = tx.AccessList().ProtoEncode()
protoTx.Value = tx.Value().Bytes()
protoTx.Data = tx.Data()
if tx.Data() == nil {
protoTx.Data = []byte{}
} else {
protoTx.Data = tx.Data()
}
if tx.To() != nil {
protoTx.To = tx.To().Bytes()
}
Expand Down Expand Up @@ -216,15 +220,15 @@ func (tx *Transaction) ProtoDecode(protoTx *ProtoTransaction, location common.Lo
if protoTx.Value == nil {
return errors.New("missing required field 'Value' in ProtoTransaction")
}
if protoTx.Data == nil {
return errors.New("missing required field 'Data' in ProtoTransaction")
}
if protoTx.GasFeeCap == nil {
return errors.New("missing required field 'GasFeeCap' in ProtoTransaction")
}
if protoTx.GasTipCap == nil {
return errors.New("missing required field 'GasTipCap' in ProtoTransaction")
}
if protoTx.Data == nil {
return errors.New("missing required field 'Data' in ProtoTransaction")
}
var itx InternalTx
itx.AccessList = AccessList{}
itx.AccessList.ProtoDecode(protoTx.GetAccessList(), location)
Expand All @@ -239,7 +243,11 @@ func (tx *Transaction) ProtoDecode(protoTx *ProtoTransaction, location common.Lo
itx.GasTipCap = new(big.Int).SetBytes(protoTx.GetGasTipCap())
itx.GasFeeCap = new(big.Int).SetBytes(protoTx.GetGasFeeCap())
itx.Gas = protoTx.GetGas()
itx.Value = new(big.Int).SetBytes(protoTx.GetValue())
if len(protoTx.GetValue()) == 0 {
itx.Value = common.Big0
} else {
itx.Value = new(big.Int).SetBytes(protoTx.GetValue())
}
itx.Data = protoTx.GetData()
if protoTx.V == nil {
return errors.New("missing required field 'V' in InternalTx")
Expand Down Expand Up @@ -431,11 +439,15 @@ func (tx *Transaction) ProtoEncodeTxSigningData() *ProtoTransaction {
protoTxSigningData.Gas = &gas
protoTxSigningData.AccessList = tx.AccessList().ProtoEncode()
protoTxSigningData.Value = tx.Value().Bytes()
protoTxSigningData.Data = tx.Data()
if tx.To() != nil {
protoTxSigningData.To = tx.To().Bytes()
if tx.Data() == nil {
protoTxSigningData.Data = []byte{}
} else {
protoTxSigningData.Data = tx.Data()
}
if tx.To() == nil {
protoTxSigningData.To = []byte{}
} else {
protoTxSigningData.To = tx.To().Bytes()
}
protoTxSigningData.GasFeeCap = tx.GasFeeCap().Bytes()
protoTxSigningData.GasTipCap = tx.GasTipCap().Bytes()
Expand Down
134 changes: 10 additions & 124 deletions core/vm/contracts.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import (
"crypto/sha256"
"encoding/binary"
"errors"
"fmt"
"math/big"

"github.com/dominant-strategies/go-quai/common"
Expand All @@ -41,136 +42,21 @@ type PrecompiledContract interface {
Run(input []byte) ([]byte, error) // Run runs the precompiled contract
}

var TranslatedAddresses = map[common.AddressBytes]int{
common.AddressBytes(intToByteArray20(1)): 0,
common.AddressBytes(intToByteArray20(2)): 1,
common.AddressBytes(intToByteArray20(3)): 2,
common.AddressBytes(intToByteArray20(4)): 3,
common.AddressBytes(intToByteArray20(5)): 4,
common.AddressBytes(intToByteArray20(6)): 5,
common.AddressBytes(intToByteArray20(7)): 6,
common.AddressBytes(intToByteArray20(8)): 7,
common.AddressBytes(intToByteArray20(9)): 8,
}

var (
PrecompiledContracts map[common.AddressBytes]PrecompiledContract = make(map[common.AddressBytes]PrecompiledContract)
PrecompiledAddresses map[string][]common.Address = make(map[string][]common.Address)
)

func InitializePrecompiles(nodeLocation common.Location) {
PrecompiledContracts[PrecompiledAddresses[nodeLocation.Name()][0].Bytes20()] = &ecrecover{}
PrecompiledContracts[PrecompiledAddresses[nodeLocation.Name()][1].Bytes20()] = &sha256hash{}
PrecompiledContracts[PrecompiledAddresses[nodeLocation.Name()][2].Bytes20()] = &ripemd160hash{}
PrecompiledContracts[PrecompiledAddresses[nodeLocation.Name()][3].Bytes20()] = &dataCopy{}
PrecompiledContracts[PrecompiledAddresses[nodeLocation.Name()][4].Bytes20()] = &bigModExp{}
PrecompiledContracts[PrecompiledAddresses[nodeLocation.Name()][5].Bytes20()] = &bn256Add{}
PrecompiledContracts[PrecompiledAddresses[nodeLocation.Name()][6].Bytes20()] = &bn256ScalarMul{}
PrecompiledContracts[PrecompiledAddresses[nodeLocation.Name()][7].Bytes20()] = &bn256Pairing{}
PrecompiledContracts[PrecompiledAddresses[nodeLocation.Name()][8].Bytes20()] = &blake2F{}
}

func init() {

PrecompiledAddresses["cyprus1"] = []common.Address{
common.HexToAddress("0x1400000000000000000000000000000000000001", common.Location{0, 0}),
common.HexToAddress("0x1400000000000000000000000000000000000002", common.Location{0, 0}),
common.HexToAddress("0x1400000000000000000000000000000000000003", common.Location{0, 0}),
common.HexToAddress("0x1400000000000000000000000000000000000004", common.Location{0, 0}),
common.HexToAddress("0x1400000000000000000000000000000000000005", common.Location{0, 0}),
common.HexToAddress("0x1400000000000000000000000000000000000006", common.Location{0, 0}),
common.HexToAddress("0x1400000000000000000000000000000000000007", common.Location{0, 0}),
common.HexToAddress("0x1400000000000000000000000000000000000008", common.Location{0, 0}),
common.HexToAddress("0x1400000000000000000000000000000000000009", common.Location{0, 0}),
}
PrecompiledAddresses["cyprus2"] = []common.Address{
common.HexToAddress("0x2000000000000000000000000000000000000001", common.Location{0, 1}),
common.HexToAddress("0x2000000000000000000000000000000000000002", common.Location{0, 1}),
common.HexToAddress("0x2000000000000000000000000000000000000003", common.Location{0, 1}),
common.HexToAddress("0x2000000000000000000000000000000000000004", common.Location{0, 1}),
common.HexToAddress("0x2000000000000000000000000000000000000005", common.Location{0, 1}),
common.HexToAddress("0x2000000000000000000000000000000000000006", common.Location{0, 1}),
common.HexToAddress("0x2000000000000000000000000000000000000007", common.Location{0, 1}),
common.HexToAddress("0x2000000000000000000000000000000000000008", common.Location{0, 1}),
common.HexToAddress("0x2000000000000000000000000000000000000009", common.Location{0, 1}),
}
PrecompiledAddresses["cyprus3"] = []common.Address{
common.HexToAddress("0x3E00000000000000000000000000000000000001", common.Location{0, 2}),
common.HexToAddress("0x3E00000000000000000000000000000000000002", common.Location{0, 2}),
common.HexToAddress("0x3E00000000000000000000000000000000000003", common.Location{0, 2}),
common.HexToAddress("0x3E00000000000000000000000000000000000004", common.Location{0, 2}),
common.HexToAddress("0x3E00000000000000000000000000000000000005", common.Location{0, 2}),
common.HexToAddress("0x3E00000000000000000000000000000000000006", common.Location{0, 2}),
common.HexToAddress("0x3E00000000000000000000000000000000000007", common.Location{0, 2}),
common.HexToAddress("0x3E00000000000000000000000000000000000008", common.Location{0, 2}),
common.HexToAddress("0x3E00000000000000000000000000000000000009", common.Location{0, 2}),
}
PrecompiledAddresses["paxos1"] = []common.Address{
common.HexToAddress("0x5A00000000000000000000000000000000000001", common.Location{1, 0}),
common.HexToAddress("0x5A00000000000000000000000000000000000002", common.Location{1, 0}),
common.HexToAddress("0x5A00000000000000000000000000000000000003", common.Location{1, 0}),
common.HexToAddress("0x5A00000000000000000000000000000000000004", common.Location{1, 0}),
common.HexToAddress("0x5A00000000000000000000000000000000000005", common.Location{1, 0}),
common.HexToAddress("0x5A00000000000000000000000000000000000006", common.Location{1, 0}),
common.HexToAddress("0x5A00000000000000000000000000000000000007", common.Location{1, 0}),
common.HexToAddress("0x5A00000000000000000000000000000000000008", common.Location{1, 0}),
common.HexToAddress("0x5A00000000000000000000000000000000000009", common.Location{1, 0}),
}
PrecompiledAddresses["paxos2"] = []common.Address{
common.HexToAddress("0x7800000000000000000000000000000000000001", common.Location{1, 1}),
common.HexToAddress("0x7800000000000000000000000000000000000002", common.Location{1, 1}),
common.HexToAddress("0x7800000000000000000000000000000000000003", common.Location{1, 1}),
common.HexToAddress("0x7800000000000000000000000000000000000004", common.Location{1, 1}),
common.HexToAddress("0x7800000000000000000000000000000000000005", common.Location{1, 1}),
common.HexToAddress("0x7800000000000000000000000000000000000006", common.Location{1, 1}),
common.HexToAddress("0x7800000000000000000000000000000000000007", common.Location{1, 1}),
common.HexToAddress("0x7800000000000000000000000000000000000008", common.Location{1, 1}),
common.HexToAddress("0x7800000000000000000000000000000000000009", common.Location{1, 1}),
}
PrecompiledAddresses["paxos3"] = []common.Address{
common.HexToAddress("0x9600000000000000000000000000000000000001", common.Location{1, 2}),
common.HexToAddress("0x9600000000000000000000000000000000000002", common.Location{1, 2}),
common.HexToAddress("0x9600000000000000000000000000000000000003", common.Location{1, 2}),
common.HexToAddress("0x9600000000000000000000000000000000000004", common.Location{1, 2}),
common.HexToAddress("0x9600000000000000000000000000000000000005", common.Location{1, 2}),
common.HexToAddress("0x9600000000000000000000000000000000000006", common.Location{1, 2}),
common.HexToAddress("0x9600000000000000000000000000000000000007", common.Location{1, 2}),
common.HexToAddress("0x9600000000000000000000000000000000000008", common.Location{1, 2}),
common.HexToAddress("0x9600000000000000000000000000000000000009", common.Location{1, 2}),
}
PrecompiledAddresses["hydra1"] = []common.Address{
common.HexToAddress("0xB400000000000000000000000000000000000001", common.Location{2, 0}),
common.HexToAddress("0xB400000000000000000000000000000000000002", common.Location{2, 0}),
common.HexToAddress("0xB400000000000000000000000000000000000003", common.Location{2, 0}),
common.HexToAddress("0xB400000000000000000000000000000000000004", common.Location{2, 0}),
common.HexToAddress("0xB400000000000000000000000000000000000005", common.Location{2, 0}),
common.HexToAddress("0xB400000000000000000000000000000000000006", common.Location{2, 0}),
common.HexToAddress("0xB400000000000000000000000000000000000007", common.Location{2, 0}),
common.HexToAddress("0xB400000000000000000000000000000000000008", common.Location{2, 0}),
common.HexToAddress("0xB400000000000000000000000000000000000009", common.Location{2, 0}),
}
PrecompiledAddresses["hydra2"] = []common.Address{
common.HexToAddress("0xD200000000000000000000000000000000000001", common.Location{2, 1}),
common.HexToAddress("0xD200000000000000000000000000000000000002", common.Location{2, 1}),
common.HexToAddress("0xD200000000000000000000000000000000000003", common.Location{2, 1}),
common.HexToAddress("0xD200000000000000000000000000000000000004", common.Location{2, 1}),
common.HexToAddress("0xD200000000000000000000000000000000000005", common.Location{2, 1}),
common.HexToAddress("0xD200000000000000000000000000000000000006", common.Location{2, 1}),
common.HexToAddress("0xD200000000000000000000000000000000000007", common.Location{2, 1}),
common.HexToAddress("0xD200000000000000000000000000000000000008", common.Location{2, 1}),
common.HexToAddress("0xD200000000000000000000000000000000000009", common.Location{2, 1}),
}
PrecompiledAddresses["hydra3"] = []common.Address{
common.HexToAddress("0xF000000000000000000000000000000000000001", common.Location{2, 2}),
common.HexToAddress("0xF000000000000000000000000000000000000002", common.Location{2, 2}),
common.HexToAddress("0xF000000000000000000000000000000000000003", common.Location{2, 2}),
common.HexToAddress("0xF000000000000000000000000000000000000004", common.Location{2, 2}),
common.HexToAddress("0xF000000000000000000000000000000000000005", common.Location{2, 2}),
common.HexToAddress("0xF000000000000000000000000000000000000006", common.Location{2, 2}),
common.HexToAddress("0xF000000000000000000000000000000000000007", common.Location{2, 2}),
common.HexToAddress("0xF000000000000000000000000000000000000008", common.Location{2, 2}),
common.HexToAddress("0xF000000000000000000000000000000000000009", common.Location{2, 2}),
}
PrecompiledContracts[common.HexToAddressBytes(fmt.Sprintf("0x%x00000000000000000000000000000000000001", nodeLocation.BytePrefix()))] = &ecrecover{}
wizeguyy marked this conversation as resolved.
Show resolved Hide resolved
PrecompiledContracts[common.HexToAddressBytes(fmt.Sprintf("0x%x00000000000000000000000000000000000002", nodeLocation.BytePrefix()))] = &sha256hash{}
jdowning100 marked this conversation as resolved.
Show resolved Hide resolved
PrecompiledContracts[common.HexToAddressBytes(fmt.Sprintf("0x%x00000000000000000000000000000000000003", nodeLocation.BytePrefix()))] = &ripemd160hash{}
PrecompiledContracts[common.HexToAddressBytes(fmt.Sprintf("0x%x00000000000000000000000000000000000004", nodeLocation.BytePrefix()))] = &dataCopy{}
PrecompiledContracts[common.HexToAddressBytes(fmt.Sprintf("0x%x00000000000000000000000000000000000005", nodeLocation.BytePrefix()))] = &bigModExp{}
PrecompiledContracts[common.HexToAddressBytes(fmt.Sprintf("0x%x00000000000000000000000000000000000006", nodeLocation.BytePrefix()))] = &bn256Add{}
PrecompiledContracts[common.HexToAddressBytes(fmt.Sprintf("0x%x00000000000000000000000000000000000007", nodeLocation.BytePrefix()))] = &bn256ScalarMul{}
PrecompiledContracts[common.HexToAddressBytes(fmt.Sprintf("0x%x00000000000000000000000000000000000008", nodeLocation.BytePrefix()))] = &bn256Pairing{}
PrecompiledContracts[common.HexToAddressBytes(fmt.Sprintf("0x%x00000000000000000000000000000000000009", nodeLocation.BytePrefix()))] = &blake2F{}
}

// ActivePrecompiles returns the precompiles enabled with the current configuration.
Expand Down
12 changes: 9 additions & 3 deletions core/vm/evm.go
Original file line number Diff line number Diff line change
Expand Up @@ -47,10 +47,16 @@ type (
)

func (evm *EVM) precompile(addr common.Address) (PrecompiledContract, bool, common.Address) {
if index, ok := TranslatedAddresses[addr.Bytes20()]; ok {
addr = PrecompiledAddresses[evm.chainConfig.Location.Name()][index]
}
p, ok := PrecompiledContracts[addr.Bytes20()]
if !ok {
// to translate the address, we add the last byte of the address to the location-specific zero address
// to support more than 255 precompiles, we could use the last two bytes, but it's likely unnecessary
translatedAddress := common.HexToAddressBytes(fmt.Sprintf("0x%x000000000000000000000000000000000000%02x", evm.chainConfig.Location.BytePrefix(), addr.Bytes20()[19]))
p, ok = PrecompiledContracts[translatedAddress]
if ok {
addr = common.Bytes20ToAddress(translatedAddress, evm.chainConfig.Location)
}
}
return p, ok, addr
}

Expand Down
14 changes: 9 additions & 5 deletions core/worker.go
Original file line number Diff line number Diff line change
Expand Up @@ -545,7 +545,9 @@ func (w *worker) GeneratePendingHeader(block *types.Block, fill bool) (*types.He
}

if nodeCtx == common.ZONE_CTX && w.hc.ProcessingState() {
work.txs = append(work.txs, types.NewTx(&types.QiTx{})) // placeholder
if coinbase.IsInQiLedgerScope() {
work.txs = append(work.txs, types.NewTx(&types.QiTx{})) // placeholder
}
// Fill pending transactions from the txpool
w.adjustGasLimit(nil, work, block)
work.utxoFees = big.NewInt(0)
Expand All @@ -559,11 +561,13 @@ func (w *worker) GeneratePendingHeader(block *types.Block, fill bool) (*types.He
"average": common.PrettyDuration(w.fillTransactionsRollingAverage.Average()),
}).Info("Filled and sorted pending transactions")
}
coinbaseTx, err := createCoinbaseTxWithFees(work.header, work.utxoFees, work.state)
if err != nil {
return nil, err
if coinbase.IsInQiLedgerScope() {
coinbaseTx, err := createCoinbaseTxWithFees(work.header, work.utxoFees, work.state)
if err != nil {
return nil, err
}
work.txs[0] = coinbaseTx
}
work.txs[0] = coinbaseTx
}

// Create a local environment copy, avoid the data race with snapshot state.
Expand Down
8 changes: 7 additions & 1 deletion internal/quaiapi/api.go
Original file line number Diff line number Diff line change
Expand Up @@ -1496,6 +1496,9 @@ func (s *PublicTransactionPoolAPI) GetTransactionReceipt(ctx context.Context, ha

// SubmitTransaction is a helper function that submits tx to txPool and logs a message.
func SubmitTransaction(ctx context.Context, b Backend, tx *types.Transaction) (common.Hash, error) {
if tx == nil {
return common.Hash{}, errors.New("transaction is nil")
}
nodeLocation := b.NodeLocation()
nodeCtx := b.NodeCtx()
if nodeCtx != common.ZONE_CTX {
Expand Down Expand Up @@ -1555,7 +1558,10 @@ func (s *PublicTransactionPoolAPI) SendRawTransaction(ctx context.Context, input
if err != nil {
return common.Hash{}, err
}
tx.ProtoDecode(protoTransaction, s.b.NodeLocation())
err = tx.ProtoDecode(protoTransaction, s.b.NodeLocation())
if err != nil {
return common.Hash{}, err
}
return SubmitTransaction(ctx, s.b, tx)
}

Expand Down
Loading
Loading