• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

unpackdev / solgo / 6315485585

26 Sep 2023 04:15PM UTC coverage: 89.493% (+0.06%) from 89.435%
6315485585

push

github

web-flow
BitOrOperator support, metadata cbor lenght panic fix and ForDeclaration body panic fix (#117)

* BitOr support, body node in for if it's empty and bytecode in metadata fixes
* Bumping protos + unit test fixes

84 of 99 new or added lines in 4 files covered. (84.85%)

1 existing line in 1 file now uncovered.

12291 of 13734 relevant lines covered (89.49%)

0.97 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

84.27
/bytecode/metadata.go
1
package bytecode
2

3
import (
4
        "bytes"
5
        "errors"
6
        "fmt"
7
        "strconv"
8
        "strings"
9

10
        "github.com/fxamacker/cbor/v2"
11
        "github.com/mr-tron/base58"
12
        metadata_pb "github.com/unpackdev/protos/dist/go/metadata"
13
)
14

15
// Metadata represents the metadata contained in Ethereum contract creation bytecode.
16
// The structure and encoding of the metadata is defined by the Solidity compiler.
17
// More information can be found at https://docs.soliditylang.org/en/v0.8.20/metadata.html#encoding-of-the-metadata-hash-in-the-bytecode
18
type Metadata struct {
19
        executionBytecode []byte // The execution bytecode of the contract
20
        cborLength        int16  // The length of the CBOR metadata
21
        auxbytes          []byte // The raw CBOR metadata
22
        Ipfs              []byte `cbor:"ipfs"`         // The IPFS hash of the metadata, if present
23
        Bzzr1             []byte `cbor:"bzzr1"`        // The Swarm hash of the metadata, if present (version 1)
24
        Bzzr0             []byte `cbor:"bzzr0"`        // The Swarm hash of the metadata, if present (version 0)
25
        Experimental      []byte `cbor:"experimental"` // Experimental metadata, if present
26
        Solc              []byte `cbor:"solc"`         // The version of the Solidity compiler used
27
}
28

29
func (m *Metadata) ToProto() *metadata_pb.BytecodeMetadata {
1✔
30
        return &metadata_pb.BytecodeMetadata{
1✔
31
                ExecutionBytecode: m.executionBytecode,
1✔
32
                CborLength:        uint32(m.cborLength),
1✔
33
                Raw:               m.auxbytes,
1✔
34
                Ipfs:              m.GetIPFS(),
1✔
35
                Bzzr1:             m.GetBzzr1(),
1✔
36
                Bzzr0:             m.GetBzzr0(),
1✔
37
                Experimental:      m.GetExperimental(),
1✔
38
                Solc:              m.GetCompilerVersion(),
1✔
39
                Solgo:             "",
1✔
40
        }
1✔
41
}
1✔
42

43
// GetCompilerVersion returns the version of the Solidity compiler used to compile the contract.
44
func (m *Metadata) GetCompilerVersion() string {
1✔
45
        s := make([]string, 0, len(m.Solc))
1✔
46
        for _, i := range m.Solc {
2✔
47
                s = append(s, strconv.Itoa(int(i)))
1✔
48
        }
1✔
49
        return strings.Join(s, ".")
1✔
50
}
51

52
// GetExperimental returns whether the contract includes experimental metadata.
53
func (m *Metadata) GetExperimental() bool {
1✔
54
        toReturn, err := strconv.ParseBool(string(m.Experimental))
1✔
55
        if err != nil {
2✔
56
                return false
1✔
57
        }
1✔
58
        return toReturn
1✔
59
}
60

61
// GetIPFS returns the IPFS hash of the contract's metadata, if present.
62
func (m *Metadata) GetIPFS() string {
1✔
63
        return fmt.Sprintf("ipfs://%s", base58.Encode(m.Ipfs))
1✔
64
}
1✔
65

66
// GetBzzr0 returns the Swarm (version 0) hash of the contract's metadata, if present.
67
func (m *Metadata) GetBzzr0() string {
1✔
68
        return fmt.Sprintf("bzz://%s", base58.Encode(m.Bzzr0))
1✔
69
}
1✔
70

71
// GetBzzr1 returns the Swarm (version 1) hash of the contract's metadata, if present.
72
func (m *Metadata) GetBzzr1() string {
1✔
73
        return fmt.Sprintf("bzz://%s", base58.Encode(m.Bzzr1))
1✔
74
}
1✔
75

76
// GetExecutionBytecode returns the execution bytecode of the contract.
77
func (m *Metadata) GetExecutionBytecode() []byte {
1✔
78
        return m.executionBytecode
1✔
79
}
1✔
80

81
// GetAuxBytecode returns the raw CBOR metadata of the contract.
82
func (m *Metadata) GetAuxBytecode() []byte {
1✔
83
        return m.auxbytes
1✔
84
}
1✔
85

86
// GetCborLength returns the length of the CBOR metadata.
87
func (m *Metadata) GetCborLength() int16 {
1✔
88
        return m.cborLength
1✔
89
}
1✔
90

91
// AuxFound returns whether the CBOR metadata bytes are contained in the provided byte slice.
92
// This is used to verify if contract extracted cbor metadata can be found in the deployed/execution contract bytecode.
93
func (m *Metadata) AuxFound(b []byte) bool {
×
94
        return bytes.Contains(b, m.auxbytes)
×
95
}
×
96

97
// GetUrls returns the URLs of the contract's metadata.
98
func (m *Metadata) GetUrls() []string {
1✔
99
        urls := make([]string, 0)
1✔
100
        if len(m.GetIPFS()) > 7 {
2✔
101
                urls = append(urls, m.GetIPFS())
1✔
102
        }
1✔
103
        if len(m.GetBzzr0()) > 6 {
1✔
104
                urls = append(urls, m.GetBzzr1())
×
105
        }
×
106
        if len(m.GetBzzr1()) > 6 {
1✔
107
                urls = append(urls, m.GetBzzr0())
×
108
        }
×
109
        return urls
1✔
110
}
111

112
// DecodeContractMetadata decodes the metadata from Ethereum contract creation bytecode.
113
// It returns a Metadata object and an error, if any occurred during decoding.
114
func DecodeContractMetadata(bytecode []byte) (*Metadata, error) {
1✔
115
        if len(bytecode) == 0 {
2✔
116
                return nil, errors.New("provided bytecode slice is empty")
1✔
117
        }
1✔
118

119
        if bytecode[0] != 0x60 {
2✔
120
                return nil, errors.New("provided bytecode slice is not a contract")
1✔
121
        }
1✔
122

123
        toReturn := Metadata{}
1✔
124

1✔
125
        // Per solidity docs, last two bytes of the bytecode are the length of the cbor object
1✔
126
        bytesLength := 2
1✔
127

1✔
128
        // Take latest 2 bytes of the bytecode (length of the cbor object)
1✔
129
        cborLength := int(bytecode[len(bytecode)-2])<<8 | int(bytecode[len(bytecode)-1])
1✔
130
        toReturn.cborLength = int16(cborLength)
1✔
131

1✔
132
        // If the length of the cbor is more or equal to the length of the execution bytecode, it means there is no cbor
1✔
133
        if len(bytecode)-bytesLength <= 0 {
1✔
134
                return nil, errors.New("provided bytecode slice does not contain cbor metadata")
×
135
        }
×
136

137
        // Split the bytecode into execution bytecode and auxdata
138
        if len(bytecode) >= bytesLength+cborLength {
2✔
139
                toReturn.executionBytecode = bytecode[:len(bytecode)-bytesLength-cborLength]
1✔
140
                toReturn.auxbytes = bytecode[len(bytecode)-bytesLength-cborLength : len(bytecode)-bytesLength]
1✔
141

1✔
142
                if err := cbor.Unmarshal(toReturn.auxbytes, &toReturn); err != nil {
1✔
NEW
143
                        return nil, err
×
NEW
144
                }
×
NEW
145
        } else {
×
NEW
146
                return nil, errors.New("provided bytecode slice is smaller than the length of the cbor object")
×
UNCOV
147
        }
×
148

149
        return &toReturn, nil
1✔
150
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc