Skip to content

Commit

Permalink
Merge branch 'master' into panic_no_space
Browse files Browse the repository at this point in the history
  • Loading branch information
huof6829 authored Oct 12, 2022
2 parents b3d8b12 + 436b7b5 commit b6bbdd2
Show file tree
Hide file tree
Showing 15 changed files with 467 additions and 29 deletions.
10 changes: 7 additions & 3 deletions Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -22,11 +22,15 @@ COPY --from=build /go/apps/iotex-core/bin/actioninjectorv2 /usr/local/bin/iotex-
COPY --from=build /go/apps/iotex-core/bin/addrgen /usr/local/bin/iotex-addrgen
COPY --from=build /go/apps/iotex-core/bin/ioctl /usr/local/bin/ioctl

CMD [ "iotex-server"]

# logrotate log file daily
RUN apk add logrotate
RUN apk add --no-cache logrotate
COPY logrotate.conf /etc/logrotate.d/iotex
RUN mkdir -p /var/lib/
RUN touch /var/lib/logrotate.status
RUN logrotate /etc/logrotate.d/iotex
RUN echo -e "#!/bin/sh\n\n/usr/sbin/logrotate -f /etc/logrotate.d/iotex" > /etc/periodic/daily/logrotate

COPY entrypoint.sh /usr/local/bin
RUN chmod +x /usr/local/bin/entrypoint.sh
ENTRYPOINT ["/usr/local/bin/entrypoint.sh"]
CMD ["iotex-server"]
7 changes: 6 additions & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ BUILD_TARGET_XCTL=xctl
BUILD_TARGET_NEWXCTL=newxctl
BUILD_TARGET_MINICLUSTER=minicluster
BUILD_TARGET_RECOVER=recover
BUILD_TARGET_READTIP=readtip
BUILD_TARGET_IOMIGRATER=iomigrater
BUILD_TARGET_OS=$(shell go env GOOS)
BUILD_TARGET_ARCH=$(shell go env GOARCH)
Expand Down Expand Up @@ -78,7 +79,7 @@ build: ioctl
$(GOBUILD) -ldflags "$(PackageFlags)" -o ./bin/$(BUILD_TARGET_SERVER) -v ./$(BUILD_TARGET_SERVER)

.PHONY: build-all
build-all: build build-actioninjector build-addrgen build-minicluster build-staterecoverer
build-all: build build-actioninjector build-addrgen build-minicluster build-staterecoverer build-readtip

.PHONY: build-actioninjector
build-actioninjector:
Expand All @@ -96,6 +97,10 @@ build-minicluster:
build-staterecoverer:
$(GOBUILD) -o ./bin/$(BUILD_TARGET_RECOVER) -v ./tools/staterecoverer

.PHONY: build-readtip
build-readtip:
$(GOBUILD) -o ./bin/$(BUILD_TARGET_READTIP) -v ./tools/readtip

.PHONY: fmt
fmt:
$(GOCMD) fmt ./...
Expand Down
2 changes: 2 additions & 0 deletions db/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,8 @@ type Config struct {
SplitDBHeight uint64 `yaml:"splitDBHeight"`
// HistoryStateRetention is the number of blocks account/contract state will be retained
HistoryStateRetention uint64 `yaml:"historyStateRetention"`
// ReadOnly is set db to be opened in read only mode
ReadOnly bool `yaml:"readOnly"`
}

// SplitDBSize returns the configured SplitDBSizeMB
Expand Down
32 changes: 19 additions & 13 deletions db/counting_index.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ package db

import (
"fmt"
"sync/atomic"

"github.com/pkg/errors"

Expand Down Expand Up @@ -109,7 +110,7 @@ func GetCountingIndex(kv KVStore, name []byte) (CountingIndex, error) {

// Size returns the total number of keys so far
func (c *countingIndex) Size() uint64 {
return c.size
return atomic.LoadUint64(&c.size)
}

// Add inserts a value into the index
Expand All @@ -121,13 +122,14 @@ func (c *countingIndex) Add(value []byte, inBatch bool) error {
return errors.Wrap(ErrInvalid, "cannot call Add in batch mode, call Commit() first to exit batch mode")
}
b := batch.NewBatch()
b.Put(c.bucket, byteutil.Uint64ToBytesBigEndian(c.size), value, fmt.Sprintf("failed to add %d-th item", c.size+1))
b.Put(c.bucket, CountKey, byteutil.Uint64ToBytesBigEndian(c.size+1), fmt.Sprintf("failed to update size = %d", c.size+1))
size := c.Size()
b.Put(c.bucket, byteutil.Uint64ToBytesBigEndian(size), value, fmt.Sprintf("failed to add %d-th item", size+1))
b.Put(c.bucket, CountKey, byteutil.Uint64ToBytesBigEndian(size+1), fmt.Sprintf("failed to update size = %d", size+1))
b.AddFillPercent(c.bucket, 1.0)
if err := c.kvStore.WriteBatch(b); err != nil {
return err
}
c.size++
atomic.AddUint64(&c.size, 1)
return nil
}

Expand All @@ -136,22 +138,23 @@ func (c *countingIndex) addBatch(value []byte) error {
if c.batch == nil {
c.batch = batch.NewBatch()
}
c.batch.Put(c.bucket, byteutil.Uint64ToBytesBigEndian(c.size), value, fmt.Sprintf("failed to add %d-th item", c.size+1))
c.size++
size := c.Size()
c.batch.Put(c.bucket, byteutil.Uint64ToBytesBigEndian(size), value, fmt.Sprintf("failed to add %d-th item", size+1))
atomic.AddUint64(&c.size, 1)
return nil
}

// Get return value of key[slot]
func (c *countingIndex) Get(slot uint64) ([]byte, error) {
if slot >= c.size {
if slot >= c.Size() {
return nil, errors.Wrapf(ErrNotExist, "slot: %d", slot)
}
return c.kvStore.Get(c.bucket, byteutil.Uint64ToBytesBigEndian(slot))
}

// Range return value of keys [start, start+count)
func (c *countingIndex) Range(start, count uint64) ([][]byte, error) {
if start+count > c.size || count == 0 {
if start+count > c.Size() || count == 0 {
return nil, errors.Wrapf(ErrInvalid, "start: %d, count: %d", start, count)
}
return c.kvStore.Range(c.bucket, byteutil.Uint64ToBytesBigEndian(start), count)
Expand All @@ -162,11 +165,12 @@ func (c *countingIndex) Revert(count uint64) error {
if c.batch != nil {
return errors.Wrap(ErrInvalid, "cannot call Revert in batch mode, call Commit() first to exit batch mode")
}
if count == 0 || count > c.size {
size := c.Size()
if count == 0 || count > size {
return errors.Wrapf(ErrInvalid, "count: %d", count)
}
b := batch.NewBatch()
start := c.size - count
start := size - count
for i := uint64(0); i < count; i++ {
b.Delete(c.bucket, byteutil.Uint64ToBytesBigEndian(start+i), fmt.Sprintf("failed to delete %d-th item", start+i))
}
Expand All @@ -175,7 +179,7 @@ func (c *countingIndex) Revert(count uint64) error {
if err := c.kvStore.WriteBatch(b); err != nil {
return err
}
c.size = start
atomic.StoreUint64(&c.size, start)
return nil
}

Expand All @@ -191,7 +195,8 @@ func (c *countingIndex) Commit() error {
if c.batch == nil {
return nil
}
c.batch.Put(c.bucket, CountKey, byteutil.Uint64ToBytesBigEndian(c.size), fmt.Sprintf("failed to update size = %d", c.size))
size := c.Size()
c.batch.Put(c.bucket, CountKey, byteutil.Uint64ToBytesBigEndian(size), fmt.Sprintf("failed to update size = %d", size))
c.batch.AddFillPercent(c.bucket, 1.0)
if err := c.kvStore.WriteBatch(c.batch); err != nil {
return err
Expand All @@ -214,7 +219,8 @@ func (c *countingIndex) Finalize() error {
if c.batch == nil {
return ErrInvalid
}
c.batch.Put(c.bucket, CountKey, byteutil.Uint64ToBytesBigEndian(c.size), fmt.Sprintf("failed to update size = %d", c.size))
size := c.Size()
c.batch.Put(c.bucket, CountKey, byteutil.Uint64ToBytesBigEndian(size), fmt.Sprintf("failed to update size = %d", size))
c.batch.AddFillPercent(c.bucket, 1.0)
c.batch = nil
return nil
Expand Down
6 changes: 5 additions & 1 deletion db/db_bolt.go
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,11 @@ func NewBoltDB(cfg Config) *BoltDB {

// Start opens the BoltDB (creates new file if not existing yet)
func (b *BoltDB) Start(_ context.Context) error {
db, err := bolt.Open(b.path, _fileMode, nil)
opts := *bolt.DefaultOptions
if b.config.ReadOnly {
opts.ReadOnly = true
}
db, err := bolt.Open(b.path, _fileMode, &opts)
if err != nil {
return errors.Wrap(ErrIO, err.Error())
}
Expand Down
5 changes: 5 additions & 0 deletions entrypoint.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
#!/bin/sh

/usr/sbin/crond

exec "$@"
13 changes: 13 additions & 0 deletions ioctl/newcmd/did/did.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,9 @@
package did

import (
"strings"

"github.com/ethereum/go-ethereum/accounts/abi"
"github.com/spf13/cobra"

"github.com/iotexproject/iotex-core/ioctl"
Expand All @@ -19,6 +22,9 @@ var (
config.English: "Manage Decentralized Identity of IoTeX blockchain",
config.Chinese: "管理IoTeX区块链上的去中心化数字身份",
}
// _didABI is the interface of the abi encoding of did
_didABI abi.ABI
err error
)

const (
Expand All @@ -31,6 +37,13 @@ const (
DIDABI = `[{"constant": false,"inputs": [],"name": "deregisterDID","outputs": [],"payable": false,"stateMutability": "nonpayable","type": "function"},{"constant": true,"inputs": [{"internalType": "bytes","name": "did","type": "bytes"}],"name": "getHash","outputs": [{"internalType": "bytes32","name": "","type": "bytes32"}],"payable": false,"stateMutability": "view","type": "function"}, {"constant": true,"inputs": [{"internalType": "bytes","name": "did","type": "bytes"}],"name": "getURI","outputs": [{"internalType": "bytes","name": "","type": "bytes"}],"payable": false,"stateMutability": "view","type": "function"},{"constant": false,"inputs": [{"internalType": "bytes32","name": "h","type": "bytes32"},{"internalType": "bytes","name": "uri","type": "bytes"}],"name": "registerDID","outputs": [],"payable": false,"stateMutability": "nonpayable","type": "function"},{"constant": false,"inputs": [{"internalType": "bytes32","name": "h","type": "bytes32"},{"internalType": "bytes","name": "uri","type": "bytes"}],"name": "updateDID","outputs": [],"payable": false,"stateMutability": "nonpayable","type": "function"}]`
)

func init() {
_didABI, err = abi.JSON(strings.NewReader(DIDABI))
if err != nil {
panic(err)
}
}

// NewDidCmd represents the did command
func NewDidCmd(client ioctl.Client) *cobra.Command {
short, _ := client.SelectTranslation(_dIDCmdShorts)
Expand Down
79 changes: 79 additions & 0 deletions ioctl/newcmd/did/didgethash.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
// Copyright (c) 2022 IoTeX Foundation
// This is an alpha (internal) release and is not suitable for production. This source code is provided 'as is' and no
// warranties are given as to title or non-infringement, merchantability or fitness for purpose and, to the extent
// permitted by law, all liability for your use of the code is disclaimed. This source code is governed by Apache
// License 2.0 that can be found in the LICENSE file.

package did

import (
"encoding/hex"

"github.com/iotexproject/iotex-address/address"
"github.com/pkg/errors"
"github.com/spf13/cobra"

"github.com/iotexproject/iotex-core/ioctl"
"github.com/iotexproject/iotex-core/ioctl/config"
"github.com/iotexproject/iotex-core/ioctl/newcmd/action"
"github.com/iotexproject/iotex-core/ioctl/util"
)

// Multi-language support
var (
_getHashCmdUses = map[config.Language]string{
config.English: "gethash (CONTRACT_ADDRESS|ALIAS) DID",
config.Chinese: "gethash (合约地址|别名) DID",
}
_getHashCmdShorts = map[config.Language]string{
config.English: "Gethash get DID doc's hash on IoTeX blockchain",
config.Chinese: "Gethash 在IoTeX链上获取相应DID的doc hash",
}
)

// NewDidGetHash represents the did get hash command
func NewDidGetHash(client ioctl.Client) *cobra.Command {
use, _ := client.SelectTranslation(_getHashCmdUses)
short, _ := client.SelectTranslation(_getHashCmdShorts)

cmd := &cobra.Command{
Use: use,
Short: short,
Args: cobra.ExactArgs(2),
RunE: func(cmd *cobra.Command, args []string) error {
cmd.SilenceUsage = true
contract, err := client.Address(args[0])
if err != nil {
return errors.Wrap(err, "failed to get contract address")
}
addr, err := address.FromString(contract)
if err != nil {
return errors.Wrap(err, "invalid contract address")
}
bytecode, err := _didABI.Pack(_getHashName, []byte(args[1]))
if err != nil {
return errors.Wrap(err, "invalid bytecode")
}

result, err := action.Read(client, addr, "0", bytecode, contract, 20000000)
if err != nil {
return errors.Wrap(err, "failed to read contract")
}
ret, err := hex.DecodeString(result)
if err != nil {
return errors.Wrap(err, "failed to decode contract")
}
res, err := _didABI.Unpack(_getHashName, ret)
if err != nil {
return errors.New("DID does not exist")
}
out, err := util.To32Bytes(res[0])
if err != nil {
return errors.Wrap(err, "failed to convert hash to bytes")
}
cmd.Println(hex.EncodeToString(out[:]))
return nil
},
}
return cmd
}
91 changes: 91 additions & 0 deletions ioctl/newcmd/did/didgethash_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
// Copyright (c) 2022 IoTeX Foundation
// This is an alpha (internal) release and is not suitable for production. This source code is provided 'as is' and no
// warranties are given as to title or non-infringement, merchantability or fitness for purpose and, to the extent
// permitted by law, all liability for your use of the code is disclaimed. This source code is governed by Apache
// License 2.0 that can be found in the LICENSE file.

package did

import (
"encoding/hex"
"testing"

"github.com/golang/mock/gomock"
"github.com/iotexproject/iotex-proto/golang/iotexapi"
"github.com/iotexproject/iotex-proto/golang/iotexapi/mock_iotexapi"
"github.com/pkg/errors"
"github.com/stretchr/testify/require"

"github.com/iotexproject/iotex-core/ioctl/config"
"github.com/iotexproject/iotex-core/ioctl/util"
"github.com/iotexproject/iotex-core/test/identityset"
"github.com/iotexproject/iotex-core/test/mock/mock_ioctlclient"
)

func TestNewDidGetHashCmd(t *testing.T) {
require := require.New(t)
ctrl := gomock.NewController(t)
defer ctrl.Finish()
client := mock_ioctlclient.NewMockClient(ctrl)
apiServiceClient := mock_iotexapi.NewMockAPIServiceClient(ctrl)
accAddr := identityset.Address(0).String()
did := "did:io:0x11111111111111111"

client.EXPECT().SelectTranslation(gomock.Any()).Return("did", config.English).Times(12)
client.EXPECT().Address(gomock.Any()).Return(accAddr, nil).Times(4)
client.EXPECT().AddressWithDefaultIfNotExist(gomock.Any()).Return(accAddr, nil).Times(4)
client.EXPECT().APIServiceClient().Return(apiServiceClient, nil).Times(4)

t.Run("get did hash", func(t *testing.T) {
apiServiceClient.EXPECT().ReadContract(gomock.Any(), gomock.Any()).Return(&iotexapi.ReadContractResponse{
Data: hex.EncodeToString([]byte("60fe47b100000000000000000000000000000000000000000000000000000000")),
}, nil)
cmd := NewDidGetHash(client)
_, err := util.ExecuteCmd(cmd, accAddr, did)
require.NoError(err)
})

t.Run("failed to decode contract", func(t *testing.T) {
expectedErr := errors.New("failed to decode contract")
apiServiceClient.EXPECT().ReadContract(gomock.Any(), gomock.Any()).Return(&iotexapi.ReadContractResponse{
Data: "test",
}, nil)
cmd := NewDidGetHash(client)
_, err := util.ExecuteCmd(cmd, "test", did)
require.Contains(err.Error(), expectedErr.Error())
})

t.Run("DID does not exist", func(t *testing.T) {
expectedErr := errors.New("DID does not exist")
apiServiceClient.EXPECT().ReadContract(gomock.Any(), gomock.Any()).Return(&iotexapi.ReadContractResponse{
Data: hex.EncodeToString([]byte("test")),
}, nil)
cmd := NewDidGetHash(client)
_, err := util.ExecuteCmd(cmd, accAddr, did)
require.Contains(err.Error(), expectedErr.Error())
})

t.Run("failed to read contract", func(t *testing.T) {
expectedErr := errors.New("failed to read contract")
apiServiceClient.EXPECT().ReadContract(gomock.Any(), gomock.Any()).Return(nil, expectedErr)
cmd := NewDidGetHash(client)
_, err := util.ExecuteCmd(cmd, accAddr, did)
require.Contains(err.Error(), expectedErr.Error())
})

t.Run("invalid contract address", func(t *testing.T) {
expectedErr := errors.New("invalid contract address")
client.EXPECT().Address(gomock.Any()).Return("test", nil)
cmd := NewDidGetHash(client)
_, err := util.ExecuteCmd(cmd, "test", did)
require.Contains(err.Error(), expectedErr.Error())
})

t.Run("failed to get contract address", func(t *testing.T) {
expectedErr := errors.New("failed to get contract address")
client.EXPECT().Address(gomock.Any()).Return("", expectedErr)
cmd := NewDidGetHash(client)
_, err := util.ExecuteCmd(cmd, "test", did)
require.Contains(err.Error(), expectedErr.Error())
})
}
Loading

0 comments on commit b6bbdd2

Please sign in to comment.