Skip to content

Commit

Permalink
feat: block verification functions
Browse files Browse the repository at this point in the history
Copy the block verification functions from
https://github.com/cardano-foundation/cardano-ibc-incubator with minimal
modifications.

Signed-off-by: Chris Gianelloni <[email protected]>
  • Loading branch information
wolf31o2 committed May 13, 2024
1 parent c65efd3 commit df81e57
Showing 1 changed file with 114 additions and 0 deletions.
114 changes: 114 additions & 0 deletions ledger/verify_block.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
// Copyright 2024 Cardano Foundation
// Copyright 2024 Blink Labs Software
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

// This file is taken almost verbatim (including comments) from
// https://github.com/cardano-foundation/cardano-ibc-incubator

package ledger

import (
"bytes"
"encoding/hex"
"errors"
"fmt"

"github.com/blinklabs-io/gouroboros/cbor"
)

func VerifyBlock(block BlockHexCbor) (error, bool, string, uint64, uint64) {
headerCborHex := block.HeaderCbor
epochNonceHex := block.Eta0
bodyHex := block.BlockBodyCbor
slotPerKesPeriod := uint64(block.Spk)

isValid := false
vrfHex := ""

// check is KES valid
headerCborByte, headerDecodeError := hex.DecodeString(headerCborHex)
if headerDecodeError != nil {
return errors.New(fmt.Sprintf("VerifyBlock: headerCborByte decode error, %v", headerDecodeError.Error())), false, "", 0, 0

Check failure on line 42 in ledger/verify_block.go

View workflow job for this annotation

GitHub Actions / lint

S1028: should use fmt.Errorf(...) instead of errors.New(fmt.Sprintf(...)) (gosimple)
}
header, headerUnmarshalError := NewBabbageBlockHeaderFromCbor(headerCborByte)
if headerUnmarshalError != nil {
return errors.New(fmt.Sprintf("VerifyBlock: header unmarshall error, %v", headerUnmarshalError.Error())), false, "", 0, 0

Check failure on line 46 in ledger/verify_block.go

View workflow job for this annotation

GitHub Actions / lint

S1028: should use fmt.Errorf(...) instead of errors.New(fmt.Sprintf(...)) (gosimple)
}
isKesValid, errKes := VerifyKes(header, slotPerKesPeriod)
if errKes != nil {
return errors.New(fmt.Sprintf("VerifyBlock: kes invalid, %v", errKes.Error())), false, "", 0, 0

Check failure on line 50 in ledger/verify_block.go

View workflow job for this annotation

GitHub Actions / lint

S1028: should use fmt.Errorf(...) instead of errors.New(fmt.Sprintf(...)) (gosimple)
}

// check is VRF valid
// Ref: https://github.com/IntersectMBO/ouroboros-consensus/blob/de74882102236fdc4dd25aaa2552e8b3e208448c/ouroboros-consensus-protocol/src/ouroboros-consensus-protocol/Ouroboros/Consensus/Protocol/Praos.hs#L541
epochNonceByte, epochNonceDecodeError := hex.DecodeString(epochNonceHex)
if epochNonceDecodeError != nil {
return errors.New(fmt.Sprintf("VerifyBlock: epochNonceByte decode error, %v", epochNonceDecodeError.Error())), false, "", 0, 0
}
vrfBytes := header.Body.VrfKey[:]
vrfResult := header.Body.VrfResult.([]interface{})
vrfProofBytes := vrfResult[1].([]byte)
vrfOutputBytes := vrfResult[0].([]byte)
seed := MkInputVrf(int64(header.Body.Slot), epochNonceByte)
output, errVrf := VrfVerifyAndHash(vrfBytes, vrfProofBytes, seed)
if errVrf != nil {
return errors.New(fmt.Sprintf("VerifyBlock: vrf invalid, %v", errVrf.Error())), false, "", 0, 0
}
isVrfValid := bytes.Equal(output, vrfOutputBytes)

// check if block data valid
blockBodyHash := header.Body.BlockBodyHash
blockBodyHashHex := hex.EncodeToString(blockBodyHash[:])
isBodyValid, isBodyValidError := VerifyBlockBody(bodyHex, blockBodyHashHex)
if isBodyValidError != nil {
return errors.New(fmt.Sprintf("VerifyBlock: VerifyBlockBody error, %v", isBodyValidError.Error())), false, "", 0, 0
}
isValid = isKesValid && isVrfValid && isBodyValid
vrfHex = hex.EncodeToString(vrfBytes)
blockNo := header.Body.BlockNumber
slotNo := header.Body.Slot
return nil, isValid, vrfHex, blockNo, slotNo
}

func ExtractBlockData(bodyHex string) ([]UTXOOutput, []RegisCert, []DeRegisCert, error) {
rawDataBytes, rawDataBytesError := hex.DecodeString(bodyHex)
if rawDataBytesError != nil {
return nil, nil, nil, errors.New(fmt.Sprintf("ExtractBlockData: bodyHex decode error, %v", rawDataBytesError.Error()))
}
var txsRaw [][]string
_, err := cbor.Decode(rawDataBytes, &txsRaw)
if err != nil {
return nil, nil, nil, errors.New(fmt.Sprintf("ExtractBlockData: txsRaw decode error, %v", err.Error()))
}
txBodies, txBodiesError := GetTxBodies(txsRaw)
if err != nil {
return nil, nil, nil, errors.New(fmt.Sprintf("ExtractBlockData: GetTxBodies error, %v", txBodiesError.Error()))
}
uTXOOutput, regisCerts, deRegisCerts, getBlockOutputError := GetBlockOutput(txBodies)
if getBlockOutputError != nil {
return nil, nil, nil, errors.New(fmt.Sprintf("ExtractBlockData: GetBlockOutput error, %v", getBlockOutputError.Error()))
}
return uTXOOutput, regisCerts, deRegisCerts, nil
}

// These are copied from types.go

type BlockHexCbor struct {
_ struct{} `cbor:",toarray"`
Flag int
HeaderCbor string
Eta0 string
Spk int
BlockBodyCbor string
}

0 comments on commit df81e57

Please sign in to comment.