This repository has been archived by the owner on May 11, 2024. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 333
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(prover): add oracle prover flag (#194)
Co-authored-by: David <david@taiko.xyz>
- Loading branch information
1 parent
80620f8
commit ebbc725
Showing
14 changed files
with
253 additions
and
31 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,135 @@ | ||
package producer | ||
|
||
import ( | ||
"context" | ||
"crypto/ecdsa" | ||
"fmt" | ||
"math/big" | ||
|
||
"github.com/ethereum/go-ethereum/common" | ||
"github.com/ethereum/go-ethereum/core/types" | ||
"github.com/ethereum/go-ethereum/crypto" | ||
"github.com/ethereum/go-ethereum/log" | ||
"github.com/taikoxyz/taiko-client/bindings" | ||
"github.com/taikoxyz/taiko-client/bindings/encoding" | ||
"github.com/taikoxyz/taiko-client/pkg/rpc" | ||
anchorTxValidator "github.com/taikoxyz/taiko-client/prover/anchor_tx_validator" | ||
) | ||
|
||
// OracleProducer is responsible for generating a fake "zkproof" consisting | ||
// of a signature of the evidence. | ||
type OracleProducer struct { | ||
rpc *rpc.Client | ||
proverPrivKey *ecdsa.PrivateKey | ||
anchorTxValidator *anchorTxValidator.AnchorTxValidator | ||
} | ||
|
||
// NewOracleProducer creates a new NewOracleProducer instance. | ||
func NewOracleProducer( | ||
rpc *rpc.Client, | ||
proverPrivKey *ecdsa.PrivateKey, | ||
taikoL2Address common.Address, | ||
) (*OracleProducer, error) { | ||
anchorValidator, err := anchorTxValidator.New(taikoL2Address, rpc.L2ChainID, rpc) | ||
if err != nil { | ||
return nil, err | ||
} | ||
|
||
return &OracleProducer{rpc, proverPrivKey, anchorValidator}, nil | ||
} | ||
|
||
// RequestProof implements the ProofProducer interface. | ||
func (d *OracleProducer) RequestProof( | ||
ctx context.Context, | ||
opts *ProofRequestOptions, | ||
blockID *big.Int, | ||
meta *bindings.TaikoDataBlockMetadata, | ||
header *types.Header, | ||
resultCh chan *ProofWithHeader, | ||
) error { | ||
log.Info( | ||
"Request oracle proof", | ||
"blockID", blockID, | ||
"beneficiary", meta.Beneficiary, | ||
"height", header.Number, | ||
"hash", header.Hash(), | ||
) | ||
|
||
block, err := d.rpc.L2.BlockByHash(ctx, header.Hash()) | ||
if err != nil { | ||
return fmt.Errorf("failed to get L2 block with given hash %s: %w", header.Hash(), err) | ||
} | ||
|
||
anchorTx := block.Transactions()[0] | ||
if err := d.anchorTxValidator.ValidateAnchorTx(ctx, anchorTx); err != nil { | ||
return fmt.Errorf("invalid anchor transaction: %w", err) | ||
} | ||
|
||
signalRoot, err := d.anchorTxValidator.GetAnchoredSignalRoot(ctx, anchorTx) | ||
if err != nil { | ||
return err | ||
} | ||
|
||
parent, err := d.rpc.L2.BlockByHash(ctx, block.ParentHash()) | ||
if err != nil { | ||
return err | ||
} | ||
|
||
blockInfo, err := d.rpc.TaikoL1.GetBlock(nil, blockID) | ||
if err != nil { | ||
return err | ||
} | ||
|
||
// signature should be done with proof set to nil, verifierID set to 0, | ||
// and prover set to 0 address. | ||
evidence := &encoding.TaikoL1Evidence{ | ||
MetaHash: blockInfo.MetaHash, | ||
ParentHash: block.ParentHash(), | ||
BlockHash: block.Hash(), | ||
SignalRoot: signalRoot, | ||
Graffiti: [32]byte{}, | ||
Prover: common.HexToAddress("0x0000000000000000000000000000000000000000"), | ||
ParentGasUsed: uint32(parent.GasUsed()), | ||
GasUsed: uint32(block.GasUsed()), | ||
VerifierId: 0, | ||
Proof: nil, | ||
} | ||
|
||
proof, _, err := hashAndSignForOracleProof(evidence, d.proverPrivKey) | ||
if err != nil { | ||
return fmt.Errorf("failed to sign evidence: %w", err) | ||
} | ||
|
||
resultCh <- &ProofWithHeader{ | ||
BlockID: blockID, | ||
Header: header, | ||
Meta: meta, | ||
ZkProof: proof, | ||
} | ||
|
||
return nil | ||
} | ||
|
||
// HashSignAndSetEvidenceForOracleProof hashes and signs the TaikoL1Evidence according to the | ||
// protocol spec to generate an "oracle proof" via the signature and v value. | ||
func hashAndSignForOracleProof( | ||
evidence *encoding.TaikoL1Evidence, | ||
privateKey *ecdsa.PrivateKey, | ||
) ([]byte, uint8, error) { | ||
inputToSign, err := encoding.EncodeProveBlockInput(evidence) | ||
if err != nil { | ||
return nil, 0, fmt.Errorf("failed to encode TaikoL1.proveBlock inputs: %w", err) | ||
} | ||
|
||
hashed := crypto.Keccak256Hash(inputToSign) | ||
|
||
sig, err := crypto.Sign(hashed.Bytes(), privateKey) | ||
if err != nil { | ||
return nil, 0, fmt.Errorf("failed to sign TaikoL1Evidence: %w", err) | ||
} | ||
|
||
// add 27 to be able to be ecrecover in solidity | ||
v := uint8(int(sig[64])) + 27 | ||
|
||
return sig, v, nil | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,62 @@ | ||
package producer | ||
|
||
import ( | ||
"crypto/ecdsa" | ||
"crypto/elliptic" | ||
"math/big" | ||
"math/rand" | ||
"os" | ||
"testing" | ||
|
||
"github.com/ethereum/go-ethereum/common" | ||
"github.com/ethereum/go-ethereum/crypto" | ||
"github.com/stretchr/testify/require" | ||
"github.com/taikoxyz/taiko-client/bindings/encoding" | ||
) | ||
|
||
// randomHash generates a random blob of data and returns it as a hash. | ||
func randomHash() common.Hash { | ||
var hash common.Hash | ||
if n, err := rand.Read(hash[:]); n != common.HashLength || err != nil { | ||
panic(err) | ||
} | ||
return hash | ||
} | ||
|
||
func TestHashAndSignOracleProof(t *testing.T) { | ||
evidence := &encoding.TaikoL1Evidence{ | ||
MetaHash: randomHash(), | ||
BlockHash: randomHash(), | ||
ParentHash: randomHash(), | ||
SignalRoot: randomHash(), | ||
Graffiti: randomHash(), | ||
Prover: common.BigToAddress(new(big.Int).SetUint64(rand.Uint64())), | ||
ParentGasUsed: 1024, | ||
GasUsed: 1024, | ||
VerifierId: 0, | ||
Proof: nil, | ||
} | ||
|
||
privateKey, err := crypto.HexToECDSA(os.Getenv("L1_PROVER_PRIVATE_KEY")) | ||
require.Nil(t, err) | ||
|
||
publicKey := privateKey.Public() | ||
|
||
publicKeyECDSA, ok := publicKey.(*ecdsa.PublicKey) | ||
require.True(t, ok) | ||
|
||
input, err := encoding.EncodeProveBlockInput(evidence) | ||
require.Nil(t, err) | ||
|
||
hash := crypto.Keccak256Hash(input) | ||
|
||
sig, _, err := hashAndSignForOracleProof(evidence, privateKey) | ||
require.Nil(t, err) | ||
|
||
pubKey, err := crypto.Ecrecover(hash.Bytes(), sig) | ||
require.Nil(t, err) | ||
isValid := crypto.VerifySignature(pubKey, hash.Bytes(), sig[:64]) | ||
require.True(t, isValid) | ||
|
||
require.Equal(t, elliptic.Marshal(publicKeyECDSA, publicKeyECDSA.X, publicKeyECDSA.Y), pubKey) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.