Skip to content

Commit 13e9ea3

Browse files
committed
introduce Contract struct with storage operations
1 parent 98b884c commit 13e9ea3

File tree

7 files changed

+205
-2
lines changed

7 files changed

+205
-2
lines changed

protocol/contract.go

Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
package protocol
2+
3+
import (
4+
"bytes"
5+
"encoding/gob"
6+
"fmt"
7+
)
8+
9+
type Contract struct {
10+
Address [64]byte // 64 Byte
11+
Issuer [64]byte // 64 Byte
12+
Balance uint64 // 8 Byte
13+
Contract []byte // Arbitrary length
14+
ContractVariables []ByteArray // Arbitrary length
15+
}
16+
17+
func NewContract(address [64]byte,
18+
issuer [64]byte,
19+
balance uint64,
20+
contract []byte,
21+
contractVariables []ByteArray) Contract {
22+
23+
return Contract {
24+
address,
25+
issuer,
26+
balance,
27+
contract,
28+
contractVariables,
29+
}
30+
}
31+
32+
func (contract *Contract) Hash() [32]byte {
33+
if contract == nil {
34+
return [32]byte{}
35+
}
36+
37+
return SerializeHashContent(contract.Address)
38+
}
39+
40+
func (contract *Contract) Encode() []byte {
41+
if contract == nil {
42+
return nil
43+
}
44+
45+
encoded := Contract{
46+
Address: contract.Address,
47+
Issuer: contract.Issuer,
48+
Balance: contract.Balance,
49+
Contract: contract.Contract,
50+
ContractVariables: contract.ContractVariables,
51+
}
52+
53+
buffer := new(bytes.Buffer)
54+
gob.NewEncoder(buffer).Encode(encoded)
55+
return buffer.Bytes()
56+
}
57+
58+
func (*Contract) Decode(encoded []byte) (contract *Contract) {
59+
var decoded Contract
60+
buffer := bytes.NewBuffer(encoded)
61+
decoder := gob.NewDecoder(buffer)
62+
decoder.Decode(&decoded)
63+
return &decoded
64+
}
65+
66+
func (contract Contract) String() string {
67+
addressHash := contract.Hash()
68+
return fmt.Sprintf(
69+
"Hash: %x, " +
70+
"Address: %x, " +
71+
"Issuer: %x, " +
72+
"Balance: %v, " +
73+
"Contract: %v, " +
74+
"ContractVariables: %v",
75+
addressHash[0:8],
76+
contract.Address[0:8],
77+
contract.Issuer[0:8],
78+
contract.Balance,
79+
contract.Contract,
80+
contract.ContractVariables)
81+
}

protocol/contract_test.go

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
package protocol
2+
3+
import (
4+
"math/rand"
5+
"reflect"
6+
"testing"
7+
)
8+
9+
func TestContractCreation(t *testing.T) {
10+
createdContract := NewContract(accA.Address, accA.Issuer, accA.Balance, accA.Contract, accA.ContractVariables)
11+
12+
if !reflect.DeepEqual(createdContract.Address, accA.Address) {
13+
t.Errorf("Address does not match the given one: %x vs. %x", createdContract.Address, accA.Address)
14+
}
15+
16+
if !reflect.DeepEqual(createdContract.Issuer, accA.Issuer) {
17+
t.Errorf("Issuer does not match the given one: %x vs. %x", createdContract.Issuer, accA.Issuer)
18+
}
19+
20+
if !reflect.DeepEqual(createdContract.Balance, accA.Balance) {
21+
t.Errorf("Balance does not match the given one: %v vs. %v", createdContract.Balance, accA.Balance)
22+
}
23+
24+
if !reflect.DeepEqual(createdContract.Contract, accA.Contract) {
25+
t.Errorf("Contract does not match the given one: %x vs. %x", createdContract.Contract, accA.Contract)
26+
}
27+
28+
if !reflect.DeepEqual(createdContract.ContractVariables, accA.ContractVariables) {
29+
t.Errorf("ContractVariables does not match the given one: %x vs. %x", createdContract.ContractVariables, accA.ContractVariables)
30+
}
31+
}
32+
33+
func TestContractHash(t *testing.T) {
34+
var address [64]byte
35+
rand.Read(address[:])
36+
37+
hash1 := accA.Hash()
38+
39+
if !reflect.DeepEqual(hash1, accA.Hash()) {
40+
t.Errorf("Contract hashing failed!")
41+
}
42+
43+
accA.Address = address
44+
hash2 :=accA.Hash()
45+
46+
if reflect.DeepEqual(hash1, hash2) {
47+
t.Errorf("Contract hashing failed!")
48+
}
49+
}
50+
51+
func TestContractSerialization(t *testing.T) {
52+
addTestingAccounts()
53+
54+
accA.Balance = 1000
55+
accA.IsStaking = true
56+
accA.TxCnt = 5
57+
58+
var compareContract *Contract
59+
encodedContract := accA.Encode()
60+
compareContract = compareContract.Decode(encodedContract)
61+
62+
if !reflect.DeepEqual(accA, compareContract) {
63+
t.Error("Contract encoding/decoding failed!")
64+
}
65+
}

storage/delete.go

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,14 @@ func DeleteAccount(address [64]byte) error {
6868
})
6969
}
7070

71+
func DeleteContract(address [64]byte) error {
72+
delete(AccountState, address)
73+
return db.Update(func(tx *bolt.Tx) error {
74+
b := tx.Bucket([]byte(ACCOUNTS_BUCKET))
75+
return b.Delete(address[:])
76+
})
77+
}
78+
7179
func DeleteAll() (err error) {
7280
//Delete in-memory storage
7381
for key := range txMemPool {

storage/read.go

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -131,6 +131,19 @@ func ReadAccounts() (accounts []*protocol.Account, err error) {
131131
return accounts, err
132132
}
133133

134+
func ReadContracts() (contracts []*protocol.Contract, err error) {
135+
err = db.View(func(tx *bolt.Tx) error {
136+
b := tx.Bucket([]byte(CONTRACTS_BUCKET))
137+
return b.ForEach(func(k, v []byte) error {
138+
var contract *protocol.Contract
139+
contract = contract.Decode(v)
140+
contracts = append(contracts, contract)
141+
return nil
142+
})
143+
})
144+
return contracts, err
145+
}
146+
134147
func ReadGenesis() (genesis *protocol.Genesis, err error) {
135148
err = db.View(func(tx *bolt.Tx) error {
136149
b := tx.Bucket([]byte(GENESIS_BUCKET))

storage/storage.go

Lines changed: 22 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,11 +13,12 @@ var (
1313
db *bolt.DB
1414
logger *log.Logger
1515
AccountState = make(map[[64]byte]*protocol.Account)
16+
ContractState = make(map[[64]byte]*protocol.Contract)
1617
RootKeys = make(map[[64]byte]*protocol.Account)
1718
txMemPool = make(map[[32]byte]protocol.Transaction)
1819
AllClosedBlocksAsc []*protocol.Block
1920
BootstrapServer string
20-
Buckets []string
21+
Buckets []string
2122
)
2223

2324
const (
@@ -30,6 +31,7 @@ const (
3031
CLOSEDCONFIGS_BUCKET = "closedconfigs"
3132
LASTCLOSEDBLOCK_BUCKET = "lastclosedblock"
3233
ACCOUNTS_BUCKET = "accounts"
34+
CONTRACTS_BUCKET = "contracts"
3335
GENESIS_BUCKET = "genesis"
3436
)
3537

@@ -47,6 +49,7 @@ func Init(dbname string, bootstrapIpport string) error {
4749
CLOSEDCONFIGS_BUCKET,
4850
LASTCLOSEDBLOCK_BUCKET,
4951
ACCOUNTS_BUCKET,
52+
CONTRACTS_BUCKET,
5053
GENESIS_BUCKET,
5154
}
5255

@@ -69,6 +72,11 @@ func Init(dbname string, bootstrapIpport string) error {
6972
return err
7073
}
7174

75+
err = loadContractState()
76+
if err != nil {
77+
return err
78+
}
79+
7280
return nil
7381
}
7482

@@ -79,7 +87,19 @@ func loadAccountState() error {
7987
}
8088

8189
for _, acc := range accounts {
82-
State[acc.Address] = acc
90+
AccountState[acc.Address] = acc
91+
}
92+
return nil
93+
}
94+
95+
func loadContractState() error {
96+
contracts, err := ReadContracts()
97+
if err != nil {
98+
return err
99+
}
100+
101+
for _, contract := range contracts {
102+
ContractState[contract.Address] = contract
83103
}
84104
return nil
85105
}

storage/utils.go

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,14 @@ func GetAccount(pubKey [64]byte) (acc *protocol.Account, err error) {
2121
}
2222
}
2323

24+
func GetContract(address [64]byte) (contract *protocol.Contract, err error) {
25+
if contract = ContractState[address]; contract != nil {
26+
return contract, nil
27+
} else {
28+
return nil, errors.New(fmt.Sprintf("Contract (%x) not in the state.", address[0:8]))
29+
}
30+
}
31+
2432
func GetRootAccount(pubKey [64]byte) (acc *protocol.Account, err error) {
2533
if IsRootKey(pubKey) {
2634
acc, err = GetAccount(pubKey)

storage/write.go

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,14 @@ func WriteAccount(account *protocol.Account) error {
5959
})
6060
}
6161

62+
func WriteContract(contract *protocol.Contract) error {
63+
ContractState[contract.Address] = contract
64+
return db.Update(func(tx *bolt.Tx) error {
65+
b := tx.Bucket([]byte(CONTRACTS_BUCKET))
66+
return b.Put(contract.Address[:], contract.Encode())
67+
})
68+
}
69+
6270
func WriteGenesis(genesis *protocol.Genesis) error {
6371
return db.Update(func(tx *bolt.Tx) error {
6472
b := tx.Bucket([]byte(GENESIS_BUCKET))

0 commit comments

Comments
 (0)