Skip to content

Commit

Permalink
Merge branch 'master' into consistent-no-ticket-error
Browse files Browse the repository at this point in the history
  • Loading branch information
PlasmaPower authored Jul 22, 2022
2 parents b20b30f + 9fbb20d commit 76f762e
Show file tree
Hide file tree
Showing 52 changed files with 832 additions and 293 deletions.
1 change: 1 addition & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ COPY ./arbos ./arbos
COPY ./arbstate ./arbstate
COPY ./blsSignatures ./blsSignatures
COPY ./cmd/replay ./cmd/replay
COPY ./das/dastree ./das/dastree
COPY ./precompiles ./precompiles
COPY ./statetransfer ./statetransfer
COPY ./util ./util
Expand Down
42 changes: 34 additions & 8 deletions arbstate/das_reader.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,14 +12,15 @@ import (
"fmt"
"io"

"github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/common"

"github.com/offchainlabs/nitro/arbos/util"
"github.com/offchainlabs/nitro/blsSignatures"
"github.com/offchainlabs/nitro/das/dastree"
)

type DataAvailabilityReader interface {
GetByHash(ctx context.Context, hash []byte) ([]byte, error)
GetByHash(ctx context.Context, hash common.Hash) ([]byte, error)
HealthCheck(ctx context.Context) error
ExpirationPolicy(ctx context.Context) (ExpirationPolicy, error)
}
Expand All @@ -30,6 +31,10 @@ var ErrHashMismatch = errors.New("Result does not match expected hash")
// which will retrieve the full batch data.
const DASMessageHeaderFlag byte = 0x80

// Indicates that this DAS certificate data employs the new merkelization strategy.
// Ignored when DASMessageHeaderFlag is not set.
const TreeDASMessageHeaderFlag byte = 0x08

// Indicates that this message was authenticated by L1. Currently unused.
const L1AuthenticatedMessageHeaderFlag byte = 0x40

Expand All @@ -43,6 +48,10 @@ func IsDASMessageHeaderByte(header byte) bool {
return (DASMessageHeaderFlag & header) > 0
}

func IsTreeDASMessageHeaderByte(header byte) bool {
return (TreeDASMessageHeaderFlag & header) > 0
}

func IsZeroheavyEncodedHeaderByte(header byte) bool {
return (ZeroheavyMessageHeaderFlag & header) > 0
}
Expand All @@ -57,6 +66,7 @@ type DataAvailabilityCertificate struct {
Timeout uint64
SignersMask uint64
Sig blsSignatures.Signature
Version uint8
}

func DeserializeDASCertFrom(rd io.Reader) (c *DataAvailabilityCertificate, err error) {
Expand Down Expand Up @@ -88,6 +98,15 @@ func DeserializeDASCertFrom(rd io.Reader) (c *DataAvailabilityCertificate, err e
}
c.Timeout = binary.BigEndian.Uint64(timeoutBuf[:])

if IsTreeDASMessageHeaderByte(header) {
var versionBuf [1]byte
_, err = io.ReadFull(r, versionBuf[:])
if err != nil {
return nil, err
}
c.Version = versionBuf[0]
}

var signersMaskBuf [8]byte
_, err = io.ReadFull(r, signersMaskBuf[:])
if err != nil {
Expand All @@ -109,25 +128,29 @@ func DeserializeDASCertFrom(rd io.Reader) (c *DataAvailabilityCertificate, err e
}

func (c *DataAvailabilityCertificate) SerializeSignableFields() []byte {
buf := make([]byte, 0, 32+8)
buf := make([]byte, 0, 32+9)
buf = append(buf, c.DataHash[:]...)

var intData [8]byte
binary.BigEndian.PutUint64(intData[:], c.Timeout)
buf = append(buf, intData[:]...)

if c.Version != 0 {
buf = append(buf, c.Version)
}

return buf
}

func (cert *DataAvailabilityCertificate) RecoverKeyset(
ctx context.Context,
da DataAvailabilityReader,
) (*DataAvailabilityKeyset, error) {
keysetBytes, err := da.GetByHash(ctx, cert.KeysetHash[:])
keysetBytes, err := da.GetByHash(ctx, cert.KeysetHash)
if err != nil {
return nil, err
}
if !bytes.Equal(crypto.Keccak256(keysetBytes), cert.KeysetHash[:]) {
if !dastree.ValidHash(cert.KeysetHash, keysetBytes) {
return nil, errors.New("keyset hash does not match cert")
}
return DeserializeKeyset(bytes.NewReader(keysetBytes))
Expand Down Expand Up @@ -168,12 +191,15 @@ func (keyset *DataAvailabilityKeyset) Serialize(wr io.Writer) error {
return nil
}

func (keyset *DataAvailabilityKeyset) Hash() ([]byte, error) {
func (keyset *DataAvailabilityKeyset) Hash() (common.Hash, error) {
wr := bytes.NewBuffer([]byte{})
if err := keyset.Serialize(wr); err != nil {
return nil, err
return common.Hash{}, err
}
if wr.Len() > dastree.BinSize {
return common.Hash{}, errors.New("keyset too large")
}
return crypto.Keccak256(wr.Bytes()), nil
return dastree.Hash(wr.Bytes()), nil
}

func DeserializeKeyset(rd io.Reader) (*DataAvailabilityKeyset, error) {
Expand Down
49 changes: 41 additions & 8 deletions arbstate/inbox.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import (

"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/crypto"
"github.com/offchainlabs/nitro/das/dastree"
"github.com/offchainlabs/nitro/zeroheavy"

"github.com/ethereum/go-ethereum/log"
Expand Down Expand Up @@ -138,17 +139,41 @@ func RecoverPayloadFromDasBatch(
log.Error("Failed to deserialize DAS message", "err", err)
return nil, nil
}
keysetPreimage, err := dasReader.GetByHash(ctx, cert.KeysetHash[:])
if err == nil && !bytes.Equal(cert.KeysetHash[:], crypto.Keccak256(keysetPreimage)) {
err = ErrHashMismatch
version := cert.Version

checkPreimage := func(hash common.Hash, preimage []byte, message string) error {
switch {
case version == 0 && crypto.Keccak256Hash(preimage) != hash:
fallthrough
case version == 1 && dastree.Hash(preimage) != hash:
log.Error(message, "err", ErrHashMismatch, "version", version)
return ErrHashMismatch
case version >= 2:
log.Error(
"Committee signed unsuported certificate format",
"version", version, "hash", hash, "payload", preimage,
)
panic("node software out of date")
}
return nil
}
recordPreimage := func(key common.Hash, value []byte) {
preimages[key] = value
}

keysetPreimage, err := dasReader.GetByHash(ctx, cert.KeysetHash)
keysetHash := cert.KeysetHash
if err == nil {
err = checkPreimage(keysetHash, keysetPreimage, "Keyset hash mismatch")
}
if err != nil {
log.Error("Couldn't get keyset", "err", err)
return nil, err
}
if preimages != nil {
preimages[common.BytesToHash(cert.KeysetHash[:])] = keysetPreimage
dastree.RecordHash(recordPreimage, keysetPreimage)
}

keyset, err := DeserializeKeyset(bytes.NewReader(keysetPreimage))
if err != nil {
log.Error("Couldn't deserialize keyset", "err", err)
Expand All @@ -159,21 +184,29 @@ func RecoverPayloadFromDasBatch(
log.Error("Bad signature on DAS batch", "err", err)
return nil, nil
}

maxTimestamp := binary.BigEndian.Uint64(sequencerMsg[8:16])
if cert.Timeout < maxTimestamp+MinLifetimeSecondsForDataAvailabilityCert {
log.Error("Data availability cert expires too soon", "err", "")
return nil, nil
}
payload, err := dasReader.GetByHash(ctx, cert.DataHash[:])
if err == nil && !bytes.Equal(crypto.Keccak256(payload), cert.DataHash[:]) {
err = ErrHashMismatch

dataHash := cert.DataHash
payload, err := dasReader.GetByHash(ctx, dataHash)
if err == nil {
err = checkPreimage(dataHash, payload, "batch hash mismatch")
}
if err != nil {
log.Error("Couldn't fetch DAS batch contents", "err", err)
return nil, err
}

if preimages != nil {
preimages[common.BytesToHash(cert.DataHash[:])] = payload
if version == 0 {
preimages[dataHash] = payload
} else {
dastree.RecordHash(recordPreimage, payload)
}
}

return payload, nil
Expand Down
5 changes: 3 additions & 2 deletions cmd/datool/datool.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import (
"strings"
"time"

"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/common/hexutil"
"github.com/offchainlabs/nitro/cmd/genericconf"

Expand Down Expand Up @@ -174,7 +175,7 @@ func startRPCClientGetByHash(args []string) error {
}

ctx := context.Background()
message, err := client.GetByHash(ctx, decodedHash)
message, err := client.GetByHash(ctx, common.BytesToHash(decodedHash))
if err != nil {
return err
}
Expand Down Expand Up @@ -235,7 +236,7 @@ func startRESTClientGetByHash(args []string) error {
}

ctx := context.Background()
message, err := client.GetByHash(ctx, decodedHash)
message, err := client.GetByHash(ctx, common.BytesToHash(decodedHash))
if err != nil {
return err
}
Expand Down
87 changes: 87 additions & 0 deletions cmd/one-time-das-upgrade/upgrade.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
// Copyright 2022, Offchain Labs, Inc.
// For license information, see https://github.com/nitro/blob/master/LICENSE

package main

import (
"encoding/hex"
"fmt"
"io/fs"
"os"
"path/filepath"

"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/crypto"
"github.com/offchainlabs/nitro/das/dastree"
"github.com/offchainlabs/nitro/util/colors"
)

func main() {
args := os.Args
if len(args) < 2 {
panic("Usage: upgrade <path>")
}

path := filepath.FromSlash(args[1])
info, err := os.Stat(path)
if err != nil {
panic(fmt.Sprintf("failed to open directory: %v\n%v", path, err))
}
if !info.IsDir() {
panic(fmt.Sprintf("path %v is not a directory", path))
}

println("upgrading das files in directory", path)

renames := make(map[string]string)

err = filepath.Walk(path, func(path string, info fs.FileInfo, err error) error {
if err != nil {
colors.PrintRed("skipping ", path, err)
return nil
}
if info.IsDir() {
return nil
}
stem := filepath.Dir(path) + "/"
name := info.Name()
zero := false
if name[:2] == "0x" {
name = name[2:]
zero = true
}

hashbytes, err := hex.DecodeString(name)
if err != nil || len(hashbytes) != 32 {
panic(fmt.Sprintf("filename %v isn't a hash", path))
}
hash := *(*common.Hash)(hashbytes)
tree := dastree.FlatHashToTreeHash(hash)

contents, err := os.ReadFile(path)
if err != nil {
panic(fmt.Sprintf("failed to read file %v %v", path, err))
}
if crypto.Keccak256Hash(contents) != hash {
panic(fmt.Sprintf("file hash %v does not match its contents", path))
}

newName := tree.Hex()
if !zero {
newName = newName[2:]
}
renames[path] = stem + newName
return nil
})
if err != nil {
panic(err)
}

for name, rename := range renames {
println(name, colors.Grey, "=>", colors.Clear, rename)
err := os.Rename(name, rename)
if err != nil {
panic("failed to mv file")
}
}
}
6 changes: 4 additions & 2 deletions cmd/replay/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import (
"github.com/offchainlabs/nitro/arbos/arbosState"
"github.com/offchainlabs/nitro/arbos/burn"
"github.com/offchainlabs/nitro/arbstate"
"github.com/offchainlabs/nitro/das/dastree"
"github.com/offchainlabs/nitro/wavmio"
)

Expand Down Expand Up @@ -85,8 +86,8 @@ func (i WavmInbox) ReadDelayedInbox(seqNum uint64) ([]byte, error) {
type PreimageDASReader struct {
}

func (dasReader *PreimageDASReader) GetByHash(ctx context.Context, hash []byte) ([]byte, error) {
return wavmio.ResolvePreImage(common.BytesToHash(hash)), nil
func (dasReader *PreimageDASReader) GetByHash(ctx context.Context, hash common.Hash) ([]byte, error) {
return dastree.Content(hash, wavmio.ResolvePreImage)
}

func (dasReader *PreimageDASReader) HealthCheck(ctx context.Context) error {
Expand All @@ -96,6 +97,7 @@ func (dasReader *PreimageDASReader) HealthCheck(ctx context.Context) error {
func (dasReader *PreimageDASReader) ExpirationPolicy(ctx context.Context) (arbstate.ExpirationPolicy, error) {
return arbstate.DiscardImmediately, nil
}

func main() {
wavmio.StubInit()

Expand Down
4 changes: 3 additions & 1 deletion contracts/src/bridge/SequencerInbox.sol
Original file line number Diff line number Diff line change
Expand Up @@ -353,7 +353,9 @@ contract SequencerInbox is DelegateCallAware, GasRefundEnabled, ISequencerInbox
* @param keysetBytes bytes of the serialized keyset
*/
function setValidKeyset(bytes calldata keysetBytes) external override onlyRollupOwner {
bytes32 ksHash = keccak256(keysetBytes);
bytes32 ksHash = bytes32(keccak256(bytes.concat(hex"fe", keccak256(keysetBytes))));
require(keysetBytes.length < 64 * 1024, "keyset is too large");

if (dasKeySetInfo[ksHash].isValidKeyset) revert AlreadyValidDASKeyset(ksHash);
dasKeySetInfo[ksHash] = DasKeySetInfo({
isValidKeyset: true,
Expand Down
Loading

0 comments on commit 76f762e

Please sign in to comment.