ecadlabs/go-tezos

View on GitHub
block.go

Summary

Maintainability
A
0 mins
Test Coverage
package tezos

import (
    "encoding/hex"
    "encoding/json"
    "fmt"
    "time"
)

// HexBytes represents bytes as a JSON string of hexadecimal digits
type HexBytes []byte

// UnmarshalText umarshalls a hex string to bytes
func (hb *HexBytes) UnmarshalText(data []byte) error {
    dst := make([]byte, hex.DecodedLen(len(data)))
    if _, err := hex.Decode(dst, data); err != nil {
        return err
    }
    *hb = dst
    return nil
}

// BlockInfo holds information about block returned by monitor heads endpoint
type BlockInfo struct {
    Hash           string     `json:"hash" yaml:"hash"`
    Level          int        `json:"level" yaml:"level"`
    Proto          int        `json:"proto" yaml:"proto"`
    Predecessor    string     `json:"predecessor" yaml:"predecessor"`
    Timestamp      time.Time  `json:"timestamp" yaml:"timestamp"`
    ValidationPass int        `json:"validation_pass" yaml:"validation_pass"`
    OperationsHash string     `json:"operations_hash" yaml:"operations_hash"`
    Fitness        []HexBytes `json:"fitness" yaml:"fitness,flow"`
    Context        string     `json:"context" yaml:"context"`
    ProtocolData   string     `json:"protocol_data" yaml:"protocol_data"`
}

// RawBlockHeader is a part of the Tezos block data
type RawBlockHeader struct {
    Level            int        `json:"level" yaml:"level"`
    Proto            int        `json:"proto" yaml:"proto"`
    Predecessor      string     `json:"predecessor" yaml:"predecessor"`
    Timestamp        time.Time  `json:"timestamp" yaml:"timestamp"`
    ValidationPass   int        `json:"validation_pass" yaml:"validation_pass"`
    OperationsHash   string     `json:"operations_hash" yaml:"operations_hash"`
    Fitness          []HexBytes `json:"fitness" yaml:"fitness,flow"`
    Context          string     `json:"context" yaml:"context"`
    Priority         int        `json:"priority" yaml:"priority"`
    ProofOfWorkNonce HexBytes   `json:"proof_of_work_nonce" yaml:"proof_of_work_nonce,flow"`
    SeedNonceHash    string     `json:"seed_nonce_hash" yaml:"seed_nonce_hash"`
    Signature        string     `json:"signature" yaml:"signature"`
}

// TestChainStatus is a variable structure depending on the Status field
type TestChainStatus interface {
    TestChainStatus() string
}

// GenericTestChainStatus holds the common values among all TestChainStatus variants
type GenericTestChainStatus struct {
    Status string `json:"status" yaml:"status"`
}

// TestChainStatus gets the TestChainStatus's Status field
func (t *GenericTestChainStatus) TestChainStatus() string {
    return t.Status
}

// NotRunningTestChainStatus is a TestChainStatus variant for Status=not_running
type NotRunningTestChainStatus struct {
    GenericTestChainStatus
}

// ForkingTestChainStatus is a TestChainStatus variant for Status=forking
type ForkingTestChainStatus struct {
    GenericTestChainStatus
    Protocol   string `json:"protocol" yaml:"protocol"`
    Expiration string `json:"expiration" yaml:"expiration"`
}

// RunningTestChainStatus is a TestChainStatus variant for Status=running
type RunningTestChainStatus struct {
    GenericTestChainStatus
    ChainID    string `json:"chain_id" yaml:"chain_id"`
    Genesis    string `json:"genesis" yaml:"genesis"`
    Protocol   string `json:"protocol" yaml:"protocol"`
    Expiration string `json:"expiration" yaml:"expiration"`
}

// MaxOperationListLength is a part of the BlockHeaderMetadata
type MaxOperationListLength struct {
    MaxSize int `json:"max_size" yaml:"max_size"`
    MaxOp   int `json:"max_op" yaml:"max_op"`
}

// BlockHeaderMetadataLevel is a part of BlockHeaderMetadata
type BlockHeaderMetadataLevel struct {
    Level                int  `json:"level" yaml:"level"`
    LevelPosition        int  `json:"level_position" yaml:"level_position"`
    Cycle                int  `json:"cycle" yaml:"cycle"`
    CyclePosition        int  `json:"cycle_position" yaml:"cycle_position"`
    VotingPeriod         int  `json:"voting_period" yaml:"voting_period"`
    VotingPeriodPosition int  `json:"voting_period_position" yaml:"voting_period_position"`
    ExpectedCommitment   bool `json:"expected_commitment" yaml:"expected_commitment"`
}

// BlockHeaderMetadata is a part of the Tezos block data
type BlockHeaderMetadata struct {
    Protocol               string                    `json:"protocol" yaml:"protocol"`
    NextProtocol           string                    `json:"next_protocol" yaml:"next_protocol"`
    TestChainStatus        TestChainStatus           `json:"-" yaml:"-"`
    MaxOperationsTTL       int                       `json:"max_operations_ttl" yaml:"max_operations_ttl"`
    MaxOperationDataLength int                       `json:"max_operation_data_length" yaml:"max_operation_data_length"`
    MaxBlockHeaderLength   int                       `json:"max_block_header_length" yaml:"max_block_header_length"`
    MaxOperationListLength []*MaxOperationListLength `json:"max_operation_list_length" yaml:"max_operation_list_length"`
    Baker                  string                    `json:"baker" yaml:"baker"`
    Level                  BlockHeaderMetadataLevel  `json:"level" yaml:"level"`
    VotingPeriodKind       string                    `json:"voting_period_kind" yaml:"voting_period_kind"`
    NonceHash              string                    `json:"nonce_hash" yaml:"nonce_hash"`
    ConsumedGas            *BigInt                   `json:"consumed_gas" yaml:"consumed_gas"`
    Deactivated            []string                  `json:"deactivated" yaml:"deactivated"`
    BalanceUpdates         BalanceUpdates            `json:"balance_updates" yaml:"balance_updates"`
}

func unmarshalTestChainStatus(data []byte) (TestChainStatus, error) {
    var tmp GenericTestChainStatus
    if err := json.Unmarshal(data, &tmp); err != nil {
        return nil, err
    }

    var v TestChainStatus

    switch tmp.Status {
    case "not_running":
        v = &NotRunningTestChainStatus{}
    case "forking":
        v = &ForkingTestChainStatus{}
    case "running":
        v = &RunningTestChainStatus{}

    default:
        return nil, fmt.Errorf("Unknown TestChainStatus.Status: %v", tmp.Status)
    }

    if err := json.Unmarshal(data, v); err != nil {
        return nil, err
    }

    return v, nil
}

// UnmarshalJSON unmarshals the BlockHeaderMetadata JSON
func (bhm *BlockHeaderMetadata) UnmarshalJSON(data []byte) error {
    type suppressJSONUnmarshaller BlockHeaderMetadata
    if err := json.Unmarshal(data, (*suppressJSONUnmarshaller)(bhm)); err != nil {
        return err
    }

    var tmp struct {
        TestChainStatus json.RawMessage `json:"test_chain_status" yaml:"test_chain_status"`
    }

    if err := json.Unmarshal(data, &tmp); err != nil {
        return err
    }

    tcs, err := unmarshalTestChainStatus(tmp.TestChainStatus)
    if err != nil {
        return err
    }

    bhm.TestChainStatus = tcs

    return nil
}

// Block holds information about a Tezos block
type Block struct {
    Protocol   string              `json:"protocol" yaml:"protocol"`
    ChainID    string              `json:"chain_id" yaml:"chain_id"`
    Hash       string              `json:"hash" yaml:"hash"`
    Header     RawBlockHeader      `json:"header" yaml:"header"`
    Metadata   BlockHeaderMetadata `json:"metadata" yaml:"metadata"`
    Operations [][]*Operation      `json:"operations" yaml:"operations"`
}