diff --git a/event/event_cache_test.go b/event/event_cache_test.go index 35ce6d7ed..041a0650d 100644 --- a/event/event_cache_test.go +++ b/event/event_cache_test.go @@ -13,7 +13,7 @@ import ( "github.com/stretchr/testify/assert" ) -var mockInterval = 10 * time.Millisecond +var mockInterval = 40 * time.Millisecond type mockSub struct { subId string diff --git a/manager/eris-mint/evm/test/fake_app_state.go b/manager/eris-mint/evm/fake_app_state.go similarity index 97% rename from manager/eris-mint/evm/test/fake_app_state.go rename to manager/eris-mint/evm/fake_app_state.go index 9b7ac96d9..d8de25035 100644 --- a/manager/eris-mint/evm/test/fake_app_state.go +++ b/manager/eris-mint/evm/fake_app_state.go @@ -3,7 +3,6 @@ package vm import ( "fmt" - . "github.com/eris-ltd/eris-db/manager/eris-mint/evm" "github.com/eris-ltd/eris-db/manager/eris-mint/evm/sha3" . "github.com/eris-ltd/eris-db/word256" ) diff --git a/manager/eris-mint/evm/test/log_event_test.go b/manager/eris-mint/evm/log_event_test.go similarity index 97% rename from manager/eris-mint/evm/test/log_event_test.go rename to manager/eris-mint/evm/log_event_test.go index 34c8ae330..e85c79fe9 100644 --- a/manager/eris-mint/evm/test/log_event_test.go +++ b/manager/eris-mint/evm/log_event_test.go @@ -5,7 +5,6 @@ import ( "reflect" "testing" - . "github.com/eris-ltd/eris-db/manager/eris-mint/evm" . "github.com/eris-ltd/eris-db/manager/eris-mint/evm/opcodes" "github.com/eris-ltd/eris-db/txs" . "github.com/eris-ltd/eris-db/word256" diff --git a/manager/eris-mint/evm/opcodes/opcodes.go b/manager/eris-mint/evm/opcodes/opcodes.go index b4205f2fe..bdb3218a1 100644 --- a/manager/eris-mint/evm/opcodes/opcodes.go +++ b/manager/eris-mint/evm/opcodes/opcodes.go @@ -3,6 +3,7 @@ package opcodes import ( "fmt" + "github.com/eris-ltd/eris-db/word256" "gopkg.in/fatih/set.v0" ) @@ -378,6 +379,8 @@ func Bytecode(bytelikes ...interface{}) []byte { if int64(bytes[i]) != b { panic(fmt.Sprintf("The int64 %v does not fit inside a byte", b)) } + case word256.Word256: + return Concat(bytes[:i], b[:], Bytecode(bytelikes[i+1:]...)) case []byte: // splice return Concat(bytes[:i], b, Bytecode(bytelikes[i+1:]...)) diff --git a/manager/eris-mint/evm/snative.go b/manager/eris-mint/evm/snative.go index a9829919a..c74acc4d0 100644 --- a/manager/eris-mint/evm/snative.go +++ b/manager/eris-mint/evm/snative.go @@ -121,7 +121,8 @@ func SNativeContracts() map[string]SNativeContractDescription { * @return result value passed in `, "set_base", - []SolidityArg{arg("_account", SolidityAddress), + []SolidityArg{ + arg("_account", SolidityAddress), arg("_authorization", permFlagType), arg("_value", permFlagType)}, ret("result", SolidityBool), @@ -135,7 +136,8 @@ func SNativeContracts() map[string]SNativeContractDescription { * @return result whether account has base authorization set `, "has_base", - []SolidityArg{arg("_account", SolidityAddress), + []SolidityArg{ + arg("_account", SolidityAddress), arg("_authorization", permFlagType)}, ret("result", SolidityBool), ptypes.HasBase, @@ -148,7 +150,8 @@ func SNativeContracts() map[string]SNativeContractDescription { * @return authorization base authorization passed in `, "unset_base", - []SolidityArg{arg("_account", SolidityAddress), + []SolidityArg{ + arg("_account", SolidityAddress), arg("_authorization", permFlagType)}, ret("authorization", permFlagType), ptypes.UnsetBase, @@ -156,13 +159,12 @@ func SNativeContracts() map[string]SNativeContractDescription { SNativeFuncDescription{` * @notice Sets global (default) value for a base authorization - * @param _account account * @param _authorization base authorization * @param _value value of base authorization * @return authorization base authorization passed in `, "set_global", - []SolidityArg{arg("_account", SolidityAddress), + []SolidityArg{ arg("_authorization", permFlagType), arg("_value", permFlagType)}, ret("authorization", permFlagType), @@ -199,11 +201,14 @@ func NewSNativeContract(comment, name string, functions ...SNativeFuncDescriptio } } +// This function is designed to be called from the EVM once a SNative contract +// has been selected. It is also placed in a registry by registerSNativeContracts +// So it can be looked up by SNative address func (contract *SNativeContractDescription) Dispatch(appState AppState, - caller *Account, args []byte, gas *int64) (output []byte, err error) { + caller *Account, args []byte, gas *int64) (output []byte, err error) { if len(args) < FuncIDLength { return Zero256.Bytes(), fmt.Errorf("SNatives dispatch requires a 4-byte function "+ - "identifier but arguments are only %s bytes long", len(args)) + "identifier but arguments are only %s bytes long", len(args)) } function, err := contract.FunctionByID(firstFourBytes(args)) @@ -228,7 +233,6 @@ func (contract *SNativeContractDescription) Dispatch(appState AppState, return function.F(appState, caller, remainingArgs, gas) } - func (contract *SNativeContractDescription) Address() Word256 { return LeftPadWord256([]byte(contract.Name)) } diff --git a/manager/eris-mint/evm/snative_test.go b/manager/eris-mint/evm/snative_test.go index 65a94f7b5..5738d6180 100644 --- a/manager/eris-mint/evm/snative_test.go +++ b/manager/eris-mint/evm/snative_test.go @@ -4,49 +4,85 @@ import ( "encoding/hex" "testing" + . "github.com/eris-ltd/eris-db/word256" "github.com/stretchr/testify/assert" "fmt" + . "github.com/eris-ltd/eris-db/manager/eris-mint/evm/opcodes" + ptypes "github.com/eris-ltd/eris-db/permission/types" ) /* Compiling the Permissions solidity contract at (generated by Solidity() function) https://ethereum.github.io/browser-solidity yields: +Functions 3fbf7da5 add_role(address,bytes32) 744f5998 has_base(address,uint64) e8145855 has_role(address,bytes32) 28fd0194 rm_role(address,bytes32) 3f0ebb30 set_base(address,uint64,uint64) -67dc6f70 set_global(address,uint64,uint64) +d54a562d set_global(uint64,uint64) 73448c99 unset_base(address,uint64) + */ -func TestPermissionsContract(t *testing.T) { - registerNativeContracts() +func TestPermissionsContractSignatures(t *testing.T) { contract := SNativeContracts()["permissions_contract"] - assertContractFunction(t, contract, "3fbf7da5", + assertFunctionIDSignature(t, contract, "3fbf7da5", "add_role(address,bytes32)") - assertContractFunction(t, contract, "744f5998", + assertFunctionIDSignature(t, contract, "744f5998", "has_base(address,uint64)") - assertContractFunction(t, contract, "e8145855", + assertFunctionIDSignature(t, contract, "e8145855", "has_role(address,bytes32)") - assertContractFunction(t, contract, "28fd0194", + assertFunctionIDSignature(t, contract, "28fd0194", "rm_role(address,bytes32)") - assertContractFunction(t, contract, "3f0ebb30", + assertFunctionIDSignature(t, contract, "3f0ebb30", "set_base(address,uint64,uint64)") - assertContractFunction(t, contract, "67dc6f70", - "set_global(address,uint64,uint64)") + assertFunctionIDSignature(t, contract, "d54a562d", + "set_global(uint64,uint64)") - assertContractFunction(t, contract, "73448c99", + assertFunctionIDSignature(t, contract, "73448c99", "unset_base(address,uint64)") } +func TestSNativeContractDescription_Dispatch(t *testing.T) { + contract := SNativeContracts()["permissions_contract"] + state := newAppState() + caller := &Account{ + Address: addr(1,1,1), + } + grantee := &Account{ + Address: addr(2,2,2), + } + state.UpdateAccount(grantee) + + function, err := contract.FunctionByName("add_role") + if err != nil { + t.Fatalf("Could not get function: %s", err) + } + funcID := function.ID() + gas := int64(1000) + + retValue, err := contract.Dispatch(state, caller, Bytecode(funcID[:], + grantee.Address, permFlagToWord256(ptypes.CreateAccount)), &gas) + assert.Error(t, err) + if err != nil { + assert.Contains(t, err.Error(), "does not have permission") + } + + caller.Permissions = allAccountPermissions() + retValue, err = contract.Dispatch(state, caller, Bytecode(funcID[:], + grantee.Address, permFlagToWord256(ptypes.CreateAccount)), &gas) + assert.NoError(t, err) + assert.Equal(t, retValue, LeftPadBytes([]byte{1},32)) +} + func TestSNativeFuncTemplate(t *testing.T) { contract := SNativeContracts()["permissions_contract"] function, err := contract.FunctionByName("rm_role") @@ -67,11 +103,12 @@ func TestSNativeContractTemplate(t *testing.T) { fmt.Println(solidity) } +// // Helpers - -func assertContractFunction(t *testing.T, contract SNativeContractDescription, +// +func assertFunctionIDSignature(t *testing.T, contract SNativeContractDescription, funcIDHex string, expectedSignature string) { - function, err := contract.FunctionByID(fourBytesFromHex(t, funcIDHex)) + function, err := contract.FunctionByID(funcIDFromHex(t, funcIDHex)) assert.NoError(t, err, "Error retrieving SNativeFunctionDescription with ID %s", funcIDHex) if err == nil { @@ -79,7 +116,7 @@ func assertContractFunction(t *testing.T, contract SNativeContractDescription, } } -func fourBytesFromHex(t *testing.T, hexString string) [4]byte { +func funcIDFromHex(t *testing.T, hexString string) FuncID { bs, err := hex.DecodeString(hexString) assert.NoError(t, err, "Could not decode hex string '%s'", hexString) if len(bs) != 4 { @@ -89,3 +126,20 @@ func fourBytesFromHex(t *testing.T, hexString string) [4]byte { return firstFourBytes(bs) } +func permFlagToWord256(permFlag ptypes.PermFlag) Word256 { + return Uint64ToWord256(uint64(permFlag)) +} + +func addr(rightBytes... uint8) Word256 { + return LeftPadWord256(rightBytes) +} + +func allAccountPermissions() ptypes.AccountPermissions { + return ptypes.AccountPermissions{ + Base: ptypes.BasePermissions{ + Perms: ptypes.AllPermFlags, + SetBit: ptypes.AllPermFlags, + }, + Roles: []string{}, + } +} \ No newline at end of file diff --git a/manager/eris-mint/evm/test/vm_test.go b/manager/eris-mint/evm/vm_test.go similarity index 99% rename from manager/eris-mint/evm/test/vm_test.go rename to manager/eris-mint/evm/vm_test.go index 248a4377a..4911965b3 100644 --- a/manager/eris-mint/evm/test/vm_test.go +++ b/manager/eris-mint/evm/vm_test.go @@ -10,7 +10,6 @@ import ( "errors" - . "github.com/eris-ltd/eris-db/manager/eris-mint/evm" . "github.com/eris-ltd/eris-db/manager/eris-mint/evm/opcodes" ptypes "github.com/eris-ltd/eris-db/permission/types" "github.com/eris-ltd/eris-db/txs" diff --git a/manager/eris-mint/state/tx_cache.go b/manager/eris-mint/state/tx_cache.go index 87ccd9133..dc322d668 100644 --- a/manager/eris-mint/state/tx_cache.go +++ b/manager/eris-mint/state/tx_cache.go @@ -19,6 +19,8 @@ type TxCache struct { storages map[Tuple256]Word256 } +var _ vm.AppState = &TxCache{} + func NewTxCache(backend *BlockCache) *TxCache { return &TxCache{ backend: backend,