Skip to content

Commit

Permalink
[ctr/lua] prevent invalid timeout check in VM
Browse files Browse the repository at this point in the history
  • Loading branch information
Sung-Jae Woo committed Sep 8, 2021
1 parent d6e8968 commit 32a8a4b
Show file tree
Hide file tree
Showing 3 changed files with 185 additions and 178 deletions.
2 changes: 1 addition & 1 deletion contract/vm.go
Expand Up @@ -1348,7 +1348,7 @@ func (ce *executor) vmLoadCode(id []byte) {
(*C.char)(unsafe.Pointer(&ce.code[0])),
C.size_t(len(ce.code)),
hexId,
ce.ctx.service-MaxVmService,
ce.ctx.service-C.int(maxContext),
); cErrMsg != nil {
errMsg := C.GoString(cErrMsg)
ce.err = errors.New(errMsg)
Expand Down
33 changes: 20 additions & 13 deletions contract/vm_callback.go
Expand Up @@ -1368,19 +1368,26 @@ func luaCheckView(service C.int) C.int {

//export luaCheckTimeout
func luaCheckTimeout(service C.int) C.int {
// Temporarily disable timeout check to prevent contract timeout raised from chain service
// if service < BlockFactory {
// service = service + MaxVmService
// }
// if service != BlockFactory {
// return 0
// }
// select {
// case <-bpTimeout:
// return 1
// default:
// return 0
// }
if service < BlockFactory {
// Originally, MaxVmService was used instead of maxContext. service
// value can be 2 and decremented by MaxVmService(=2) during VM loading.
// That means the value of service becomes zero after the latter
// adjustment.
//
// This make the VM check block timeout in a unwanted situation. If that
// happens during the chain service is connecting block, the block chain
// becomes out of sync.
service = service + C.int(maxContext)
}
if service != BlockFactory {
return 0
}
select {
case <-bpTimeout:
return 1
default:
return 0
}
return 0
}

Expand Down
328 changes: 164 additions & 164 deletions contract/vm_test.go
Expand Up @@ -601,103 +601,103 @@ abi.register(infiniteLoop, infiniteCall, catch, contract_catch)`
}
}

// func TestInfiniteLoopOnPubNet(t *testing.T) {
// bc, err := LoadDummyChain(
// func(d *DummyChain) {
// d.timeout = 50
// },
// OnPubNet,
// )
// if err != nil {
// t.Errorf("failed to create test database: %v", err)
// }
// defer bc.Release()

// definition := `
// function infiniteLoop()
// local t = 0
// while true do
// t = t + 1
// end
// return t
// end
// function infiniteCall()
// infiniteCall()
// end
// function catch()
// return pcall(infiniteLoop)
// end
// function contract_catch()
// return contract.pcall(infiniteLoop)
// end
// abi.register(infiniteLoop, infiniteCall, catch, contract_catch)`

// err = bc.ConnectBlock(
// NewLuaTxAccount("ktlee", 100000000000000000),
// NewLuaTxDef("ktlee", "loop", 0, definition),
// )
// if err != nil {
// t.Error(err)
// }

// err = bc.ConnectBlock(
// NewLuaTxCall(
// "ktlee",
// "loop",
// 0,
// `{"Name":"infiniteLoop"}`,
// ),
// )
// errTimeout := VmTimeoutError{}
// if err == nil {
// t.Errorf("expected: %v", errTimeout)
// }
// if err != nil && !strings.Contains(err.Error(), errTimeout.Error()) {
// t.Error(err)
// }

// err = bc.ConnectBlock(
// NewLuaTxCall(
// "ktlee",
// "loop",
// 0,
// `{"Name":"catch"}`,
// ),
// )
// if err == nil {
// t.Errorf("expected: %v", errTimeout)
// }
// if err != nil && !strings.Contains(err.Error(), errTimeout.Error()) {
// t.Error(err)
// }

// err = bc.ConnectBlock(
// NewLuaTxCall(
// "ktlee",
// "loop",
// 0,
// `{"Name":"contract_catch"}`,
// ),
// )
// if err == nil {
// t.Errorf("expected: %v", errTimeout)
// }
// if err != nil && !strings.Contains(err.Error(), errTimeout.Error()) {
// t.Error(err)
// }

// err = bc.ConnectBlock(
// NewLuaTxCall(
// "ktlee",
// "loop",
// 0,
// `{"Name":"infiniteCall"}`,
// ).Fail("stack overflow"),
// )
// if err != nil {
// t.Error(err)
// }
// }
func TestInfiniteLoopOnPubNet(t *testing.T) {
bc, err := LoadDummyChain(
func(d *DummyChain) {
d.timeout = 50
},
OnPubNet,
)
if err != nil {
t.Errorf("failed to create test database: %v", err)
}
defer bc.Release()

definition := `
function infiniteLoop()
local t = 0
while true do
t = t + 1
end
return t
end
function infiniteCall()
infiniteCall()
end
function catch()
return pcall(infiniteLoop)
end
function contract_catch()
return contract.pcall(infiniteLoop)
end
abi.register(infiniteLoop, infiniteCall, catch, contract_catch)`

err = bc.ConnectBlock(
NewLuaTxAccount("ktlee", 100000000000000000),
NewLuaTxDef("ktlee", "loop", 0, definition),
)
if err != nil {
t.Error(err)
}

err = bc.ConnectBlock(
NewLuaTxCall(
"ktlee",
"loop",
0,
`{"Name":"infiniteLoop"}`,
),
)
errTimeout := VmTimeoutError{}
if err == nil {
t.Errorf("expected: %v", errTimeout)
}
if err != nil && !strings.Contains(err.Error(), errTimeout.Error()) {
t.Error(err)
}

err = bc.ConnectBlock(
NewLuaTxCall(
"ktlee",
"loop",
0,
`{"Name":"catch"}`,
),
)
if err == nil {
t.Errorf("expected: %v", errTimeout)
}
if err != nil && !strings.Contains(err.Error(), errTimeout.Error()) {
t.Error(err)
}

err = bc.ConnectBlock(
NewLuaTxCall(
"ktlee",
"loop",
0,
`{"Name":"contract_catch"}`,
),
)
if err == nil {
t.Errorf("expected: %v", errTimeout)
}
if err != nil && !strings.Contains(err.Error(), errTimeout.Error()) {
t.Error(err)
}

err = bc.ConnectBlock(
NewLuaTxCall(
"ktlee",
"loop",
0,
`{"Name":"infiniteCall"}`,
).Fail("stack overflow"),
)
if err != nil {
t.Error(err)
}
}

func TestUpdateSize(t *testing.T) {
bc, err := LoadDummyChain()
Expand Down Expand Up @@ -5365,73 +5365,73 @@ abi.register(testall)
}
}

// func TestTimeoutCnt(t *testing.T) {
// timeout := 500
// src := `
// function infinite_loop(n)
// while true do
// end
// return 0
// end

// abi.register(infinite_loop)
// `
// bc, err := LoadDummyChain(
// func(d *DummyChain) {
// d.timeout = timeout // milliseconds
// },
// OnPubNet,
// )
// if err != nil {
// t.Errorf("failed to create test database: %v", err)
// }
// defer bc.Release()

// err = bc.ConnectBlock(
// NewLuaTxAccount("ktlee", 100000000000000000),
// NewLuaTxDef("ktlee", "timeout-cnt", 0, src),
// )
// if err != nil {
// t.Error(err)
// }
// err = bc.ConnectBlock(
// NewLuaTxCall("ktlee", "timeout-cnt", 0, `{"Name": "infinite_loop"}`).Fail("contract timeout"),
// )
// if err != nil {
// t.Error(err)
// }
// err = bc.Query("timeout-cnt", `{"Name": "infinite_loop"}`, "exceeded the maximum instruction count")
// if err != nil {
// t.Error(err)
// }

// src2 := `
// function a()
// src = [[
// while true do
// end
// function b()
// end
// abi.register(b)
// ]]
// contract.deploy(src)
// end

// abi.register(a)
// `
// err = bc.ConnectBlock(
// NewLuaTxDef("ktlee", "timeout-cnt2", 0, src2),
// )
// if err != nil {
// t.Error(err)
// }
// err = bc.ConnectBlock(
// NewLuaTxCall("ktlee", "timeout-cnt2", 0, `{"Name": "a"}`).Fail("contract timeout"),
// )
// if err != nil {
// t.Error(err)
// }
// }
func TestTimeoutCnt(t *testing.T) {
timeout := 500
src := `
function infinite_loop(n)
while true do
end
return 0
end
abi.register(infinite_loop)
`
bc, err := LoadDummyChain(
func(d *DummyChain) {
d.timeout = timeout // milliseconds
},
OnPubNet,
)
if err != nil {
t.Errorf("failed to create test database: %v", err)
}
defer bc.Release()

err = bc.ConnectBlock(
NewLuaTxAccount("ktlee", 100000000000000000),
NewLuaTxDef("ktlee", "timeout-cnt", 0, src),
)
if err != nil {
t.Error(err)
}
err = bc.ConnectBlock(
NewLuaTxCall("ktlee", "timeout-cnt", 0, `{"Name": "infinite_loop"}`).Fail("contract timeout"),
)
if err != nil {
t.Error(err)
}
err = bc.Query("timeout-cnt", `{"Name": "infinite_loop"}`, "exceeded the maximum instruction count")
if err != nil {
t.Error(err)
}

src2 := `
function a()
src = [[
while true do
end
function b()
end
abi.register(b)
]]
contract.deploy(src)
end
abi.register(a)
`
err = bc.ConnectBlock(
NewLuaTxDef("ktlee", "timeout-cnt2", 0, src2),
)
if err != nil {
t.Error(err)
}
err = bc.ConnectBlock(
NewLuaTxCall("ktlee", "timeout-cnt2", 0, `{"Name": "a"}`).Fail("contract timeout"),
)
if err != nil {
t.Error(err)
}
}

func TestFeeDelegation(t *testing.T) {
definition := `
Expand Down

0 comments on commit 32a8a4b

Please sign in to comment.